// Copyright 2015, 2016 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity 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. // Parity 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 Parity. If not, see . //! Unified interfaces for RLP bytes operations on basic types //! use std::mem; use std::fmt; use std::cmp::Ordering; use std::error::Error as StdError; use bigint::prelude::{Uint, U128, U256, H64, H128, H160, H256, H512, H520, H2048}; use elastic_array::*; /// Vector like object pub trait VecLike { /// Add an element to the collection fn vec_push(&mut self, value: T); /// Add a slice to the collection fn vec_extend(&mut self, slice: &[T]); } impl VecLike for Vec where T: Copy { fn vec_push(&mut self, value: T) { Vec::::push(self, value) } fn vec_extend(&mut self, slice: &[T]) { Vec::::extend_from_slice(self, slice) } } macro_rules! impl_veclike_for_elastic_array { ($from: ident) => { impl VecLike for $from where T: Copy { fn vec_push(&mut self, value: T) { $from::::push(self, value) } fn vec_extend(&mut self, slice: &[T]) { $from::::append_slice(self, slice) } } } } impl_veclike_for_elastic_array!(ElasticArray16); impl_veclike_for_elastic_array!(ElasticArray32); impl_veclike_for_elastic_array!(ElasticArray1024); /// Converts given type to its shortest representation in bytes /// /// TODO: optimise some conversations pub trait ToBytes { /// Serialize self to byte array fn to_bytes>(&self, out: &mut V); /// Get length of serialized data in bytes fn to_bytes_len(&self) -> usize; } impl <'a> ToBytes for &'a str { fn to_bytes>(&self, out: &mut V) { out.vec_extend(self.as_bytes()); } fn to_bytes_len(&self) -> usize { self.as_bytes().len() } } impl ToBytes for String { fn to_bytes>(&self, out: &mut V) { out.vec_extend(self.as_bytes()); } fn to_bytes_len(&self) -> usize { self.len() } } impl ToBytes for u64 { fn to_bytes>(&self, out: &mut V) { let count = self.to_bytes_len(); for i in 0..count { let j = count - 1 - i; out.vec_push((*self >> (j * 8)) as u8); } } fn to_bytes_len(&self) -> usize { 8 - self.leading_zeros() as usize / 8 } } impl ToBytes for bool { fn to_bytes>(&self, out: &mut V) { out.vec_push(if *self { 1u8 } else { 0u8 }) } fn to_bytes_len(&self) -> usize { 1 } } macro_rules! impl_map_to_bytes { ($from: ident, $to: ty) => { impl ToBytes for $from { fn to_bytes>(&self, out: &mut V) { (*self as $to).to_bytes(out) } fn to_bytes_len(&self) -> usize { (*self as $to).to_bytes_len() } } } } impl_map_to_bytes!(usize, u64); impl_map_to_bytes!(u16, u64); impl_map_to_bytes!(u32, u64); macro_rules! impl_uint_to_bytes { ($name: ident) => { impl ToBytes for $name { fn to_bytes>(&self, out: &mut V) { let count = self.to_bytes_len(); for i in 0..count { let j = count - 1 - i; out.vec_push(self.byte(j)); } } fn to_bytes_len(&self) -> usize { (self.bits() + 7) / 8 } } } } impl_uint_to_bytes!(U256); impl_uint_to_bytes!(U128); macro_rules! impl_hash_to_bytes { ($name: ident) => { impl ToBytes for $name { fn to_bytes>(&self, out: &mut V) { out.vec_extend(&self); } fn to_bytes_len(&self) -> usize { self.len() } } } } impl_hash_to_bytes!(H64); impl_hash_to_bytes!(H128); impl_hash_to_bytes!(H160); impl_hash_to_bytes!(H256); impl_hash_to_bytes!(H512); impl_hash_to_bytes!(H520); impl_hash_to_bytes!(H2048); /// Error returned when `FromBytes` conversation goes wrong #[derive(Debug, PartialEq, Eq)] pub enum FromBytesError { /// Expected more RLP data DataIsTooShort, /// Extra bytes after the end of the last item DataIsTooLong, /// Integer-representation is non-canonically prefixed with zero byte(s). ZeroPrefixedInt, /// String representation is not utf-8 InvalidUtf8, } impl StdError for FromBytesError { fn description(&self) -> &str { "from_bytes error" } } impl fmt::Display for FromBytesError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&self, f) } } /// Alias for the result of `FromBytes` trait pub type FromBytesResult = Result; /// Converts to given type from its bytes representation /// /// TODO: check size of bytes before conversation and return appropriate error pub trait FromBytes: Sized { /// Create a value from bytes fn from_bytes(bytes: &[u8]) -> FromBytesResult; } impl FromBytes for String { fn from_bytes(bytes: &[u8]) -> FromBytesResult { ::std::str::from_utf8(bytes).map(|s| s.to_owned()).map_err(|_| FromBytesError::InvalidUtf8) } } macro_rules! impl_uint_from_bytes { ($to: ident) => { impl FromBytes for $to { fn from_bytes(bytes: &[u8]) -> FromBytesResult<$to> { match bytes.len() { 0 => Ok(0), l if l <= mem::size_of::<$to>() => { if bytes[0] == 0 { return Err(FromBytesError::ZeroPrefixedInt) } let mut res = 0 as $to; for i in 0..l { let shift = (l - 1 - i) * 8; res = res + ((bytes[i] as $to) << shift); } Ok(res) } _ => Err(FromBytesError::DataIsTooLong) } } } } } impl FromBytes for bool { fn from_bytes(bytes: &[u8]) -> FromBytesResult { match bytes.len() { 0 => Ok(false), 1 => Ok(bytes[0] != 0), _ => Err(FromBytesError::DataIsTooLong), } } } //impl_uint_from_bytes!(u8); impl_uint_from_bytes!(u16); impl_uint_from_bytes!(u32); impl_uint_from_bytes!(u64); impl_uint_from_bytes!(usize); macro_rules! impl_uint_from_bytes { ($name: ident, $size: expr) => { impl FromBytes for $name { fn from_bytes(bytes: &[u8]) -> FromBytesResult<$name> { if !bytes.is_empty() && bytes[0] == 0 { Err(FromBytesError::ZeroPrefixedInt) } else if bytes.len() <= $size { Ok($name::from(bytes)) } else { Err(FromBytesError::DataIsTooLong) } } } } } impl_uint_from_bytes!(U256, 32); impl_uint_from_bytes!(U128, 16); macro_rules! impl_hash_from_bytes { ($name: ident, $size: expr) => { impl FromBytes for $name { fn from_bytes(bytes: &[u8]) -> FromBytesResult<$name> { match bytes.len().cmp(&$size) { Ordering::Less => Err(FromBytesError::DataIsTooShort), Ordering::Greater => Err(FromBytesError::DataIsTooLong), Ordering::Equal => { let mut t = [0u8; $size]; t.copy_from_slice(bytes); Ok($name(t)) } } } } } } impl_hash_from_bytes!(H64, 8); impl_hash_from_bytes!(H128, 16); impl_hash_from_bytes!(H160, 20); impl_hash_from_bytes!(H256, 32); impl_hash_from_bytes!(H512, 64); impl_hash_from_bytes!(H520, 65); impl_hash_from_bytes!(H2048, 256);