// Copyright 2017 Parity Technologies (UK) Ltd. // This file is part of Polkadot. // Polkadot is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // Polkadot is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . //! Serialisation. use runtime_support::prelude::*; use runtime_support::{mem, slice}; use joiner::Joiner; use endiansensitive::EndianSensitive; /// Trait that allows zero-copy read/write of value-references to/from slices in LE format. pub trait Slicable: Sized { fn from_slice(value: &[u8]) -> Option { Self::set_as_slice(&|out, offset| if value.len() >= out.len() + offset { let value = &value[offset..]; let len = out.len(); out.copy_from_slice(&value[0..len]); true } else { false }) } fn to_vec(&self) -> Vec { self.as_slice_then(|s| s.to_vec()) } fn set_as_slice bool>(set_slice: &F) -> Option; fn as_slice_then R>(&self, f: F) -> R { f(&self.to_vec()) } fn size_of(_value: &[u8]) -> Option; } /// Trait to mark that a type is not trivially (essentially "in place") serialisable. pub trait NonTrivialSlicable: Slicable {} impl Slicable for T { fn set_as_slice bool>(fill_slice: &F) -> Option { let size = mem::size_of::(); let mut result: T = unsafe { mem::zeroed() }; let result_slice = unsafe { let ptr = &mut result as *mut _ as *mut u8; slice::from_raw_parts_mut(ptr, size) }; if fill_slice(result_slice, 0) { Some(result.from_le()) } else { None } } fn as_slice_then R>(&self, f: F) -> R { let size = mem::size_of::(); self.as_le_then(|le| { let value_slice = unsafe { let ptr = le as *const _ as *const u8; slice::from_raw_parts(ptr, size) }; f(value_slice) }) } fn size_of(_value: &[u8]) -> Option { Some(mem::size_of::()) } } impl Slicable for Vec { fn from_slice(value: &[u8]) -> Option { Some(value[4..].to_vec()) } fn set_as_slice bool>(fill_slice: &F) -> Option { u32::set_as_slice(fill_slice).and_then(|len| { let mut v = Vec::with_capacity(len as usize); unsafe { v.set_len(len as usize); } if fill_slice(&mut v, 4) { Some(v) } else { None } }) } fn to_vec(&self) -> Vec { let mut r: Vec = Vec::new().join(&(self.len() as u32)); r.extend_from_slice(&self); r } fn size_of(data: &[u8]) -> Option { u32::from_slice(&data[0..4]).map(|i| (i + 4) as usize) } } #[cfg(test)] mod tests { use super::*; #[test] fn vec_is_slicable() { let v = b"Hello world".to_vec(); v.as_slice_then(|ref slice| assert_eq!(slice, &b"\x0b\0\0\0Hello world") ); } }