diff --git a/examples/value_type.rs b/examples/value_type.rs index dad7eb6..a6827fd 100644 --- a/examples/value_type.rs +++ b/examples/value_type.rs @@ -14,7 +14,7 @@ // limitations under the License. use codec::Encode; -use scale_decode::visitor; +use scale_decode::visitor::{self, TypeId}; // A custom type we'd like to decode into: #[derive(Debug, PartialEq)] @@ -39,12 +39,12 @@ enum Value { CompactU64(u64), CompactU128(u128), Sequence(Vec), - Composite(Vec<(Option, Value)>), + Composite(Vec<(String, Value)>), Tuple(Vec), Str(String), Array(Vec), - Variant(String, Vec<(Option, Value)>), - BitSequence(visitor::types::BitSequenceValue), + Variant(String, Vec<(String, Value)>), + BitSequence(visitor::BitSequenceValue), } // Implement the `Visitor` trait to define how to go from SCALE @@ -54,66 +54,87 @@ impl visitor::Visitor for ValueVisitor { type Value = Value; type Error = visitor::DecodeError; - fn visit_bool(self, value: bool) -> Result { + fn visit_bool(self, value: bool, _type_id: TypeId) -> Result { Ok(Value::Bool(value)) } - fn visit_char(self, value: char) -> Result { + fn visit_char(self, value: char, _type_id: TypeId) -> Result { Ok(Value::Char(value)) } - fn visit_u8(self, value: u8) -> Result { + fn visit_u8(self, value: u8, _type_id: TypeId) -> Result { Ok(Value::U8(value)) } - fn visit_u16(self, value: u16) -> Result { + fn visit_u16(self, value: u16, _type_id: TypeId) -> Result { Ok(Value::U16(value)) } - fn visit_u32(self, value: u32) -> Result { + fn visit_u32(self, value: u32, _type_id: TypeId) -> Result { Ok(Value::U32(value)) } - fn visit_u64(self, value: u64) -> Result { + fn visit_u64(self, value: u64, _type_id: TypeId) -> Result { Ok(Value::U64(value)) } - fn visit_u128(self, value: u128) -> Result { + fn visit_u128(self, value: u128, _type_id: TypeId) -> Result { Ok(Value::U128(value)) } - fn visit_u256(self, value: &[u8; 32]) -> Result { + fn visit_u256(self, value: &[u8; 32], _type_id: TypeId) -> Result { Ok(Value::U256(*value)) } - fn visit_i8(self, value: i8) -> Result { + fn visit_i8(self, value: i8, _type_id: TypeId) -> Result { Ok(Value::I8(value)) } - fn visit_i16(self, value: i16) -> Result { + fn visit_i16(self, value: i16, _type_id: TypeId) -> Result { Ok(Value::I16(value)) } - fn visit_i32(self, value: i32) -> Result { + fn visit_i32(self, value: i32, _type_id: TypeId) -> Result { Ok(Value::I32(value)) } - fn visit_i64(self, value: i64) -> Result { + fn visit_i64(self, value: i64, _type_id: TypeId) -> Result { Ok(Value::I64(value)) } - fn visit_i128(self, value: i128) -> Result { + fn visit_i128(self, value: i128, _type_id: TypeId) -> Result { Ok(Value::I128(value)) } - fn visit_i256(self, value: &[u8; 32]) -> Result { + fn visit_i256(self, value: &[u8; 32], _type_id: TypeId) -> Result { Ok(Value::I256(*value)) } - fn visit_compact_u8(self, value: u8) -> Result { - Ok(Value::CompactU8(value)) + fn visit_compact_u8( + self, + value: visitor::Compact, + _type_id: TypeId, + ) -> Result { + Ok(Value::CompactU8(value.value())) } - fn visit_compact_u16(self, value: u16) -> Result { - Ok(Value::CompactU16(value)) + fn visit_compact_u16( + self, + value: visitor::Compact, + _type_id: TypeId, + ) -> Result { + Ok(Value::CompactU16(value.value())) } - fn visit_compact_u32(self, value: u32) -> Result { - Ok(Value::CompactU32(value)) + fn visit_compact_u32( + self, + value: visitor::Compact, + _type_id: TypeId, + ) -> Result { + Ok(Value::CompactU32(value.value())) } - fn visit_compact_u64(self, value: u64) -> Result { - Ok(Value::CompactU64(value)) + fn visit_compact_u64( + self, + value: visitor::Compact, + _type_id: TypeId, + ) -> Result { + Ok(Value::CompactU64(value.value())) } - fn visit_compact_u128(self, value: u128) -> Result { - Ok(Value::CompactU128(value)) + fn visit_compact_u128( + self, + value: visitor::Compact, + _type_id: TypeId, + ) -> Result { + Ok(Value::CompactU128(value.value())) } fn visit_sequence( self, - value: &mut visitor::types::Sequence<'_>, + value: &mut visitor::Sequence, + _type_id: TypeId, ) -> Result { let mut vals = vec![]; while let Some(val) = value.decode_item(ValueVisitor)? { @@ -123,17 +144,19 @@ impl visitor::Visitor for ValueVisitor { } fn visit_composite( self, - value: &mut visitor::types::Composite<'_>, + value: &mut visitor::Composite, + _type_id: TypeId, ) -> Result { let mut vals = vec![]; - while let Some((name, val)) = value.decode_item(ValueVisitor)? { - vals.push((name.map(|s| s.to_owned()), val)); + while let Some((name, val)) = value.decode_item_with_name(ValueVisitor)? { + vals.push((name.to_owned(), val)); } Ok(Value::Composite(vals)) } fn visit_tuple( self, - value: &mut visitor::types::Tuple<'_>, + value: &mut visitor::Tuple, + _type_id: TypeId, ) -> Result { let mut vals = vec![]; while let Some(val) = value.decode_item(ValueVisitor)? { @@ -141,22 +164,25 @@ impl visitor::Visitor for ValueVisitor { } Ok(Value::Tuple(vals)) } - fn visit_str(self, value: &visitor::types::Str<'_>) -> Result { + fn visit_str(self, value: visitor::Str, _type_id: TypeId) -> Result { Ok(Value::Str(value.as_str()?.to_owned())) } fn visit_variant( self, - value: &mut visitor::types::Variant<'_>, + value: &mut visitor::Variant, + _type_id: TypeId, ) -> Result { let mut vals = vec![]; - while let Some((name, val)) = value.decode_item(ValueVisitor)? { - vals.push((name.map(|s| s.to_owned()), val)); + let fields = value.fields(); + while let Some((name, val)) = fields.decode_item_with_name(ValueVisitor)? { + vals.push((name.to_owned(), val)); } Ok(Value::Variant(value.name().to_owned(), vals)) } fn visit_array( self, - value: &mut visitor::types::Array<'_>, + value: &mut visitor::Array, + _type_id: TypeId, ) -> Result { let mut vals = vec![]; while let Some(val) = value.decode_item(ValueVisitor)? { @@ -166,7 +192,8 @@ impl visitor::Visitor for ValueVisitor { } fn visit_bitsequence( self, - value: &mut visitor::types::BitSequence<'_>, + value: &mut visitor::BitSequence, + _type_id: TypeId, ) -> Result { Ok(Value::BitSequence(value.decode_bitsequence()?)) } @@ -195,8 +222,8 @@ fn main() { Value::Variant( "Bar".to_owned(), vec![ - (Some("hi".to_string()), Value::Str("hello".to_string())), - (Some("other".to_string()), Value::U128(123)), + ("hi".to_string(), Value::Str("hello".to_string())), + ("other".to_string(), Value::U128(123)), ], ) ) diff --git a/src/decode.rs b/src/decode.rs index 6a3fdc5..4983291 100644 --- a/src/decode.rs +++ b/src/decode.rs @@ -13,12 +13,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::bit_sequence::get_bitsequence_details; +use crate::utils::{bit_sequence::get_bitsequence_details, stack_vec::StackVec}; use crate::visitor::{ - types::{Array, BitSequence, Composite, Sequence, Str, Tuple, Variant}, - DecodeError, Visitor, + Array, BitSequence, Compact, CompactLocation, Composite, DecodeError, Sequence, Str, Tuple, + TypeId, Variant, Visitor, }; -use codec::{Compact, Decode}; +use codec::{self, Decode}; use scale_info::{ form::PortableForm, PortableRegistry, TypeDef, TypeDefArray, TypeDefBitSequence, TypeDefCompact, TypeDefComposite, TypeDefPrimitive, TypeDefSequence, TypeDefTuple, @@ -29,34 +29,38 @@ use scale_info::{ /// The provided pointer to the data slice will be moved forwards as needed /// depending on what was decoded, and a method on the provided [`Visitor`] /// will be called depending on the type that needs to be decoded. -pub fn decode<'a, V: Visitor>( - data: &mut &'a [u8], +pub fn decode( + data: &mut &[u8], ty_id: u32, - types: &'a PortableRegistry, + types: &PortableRegistry, visitor: V, ) -> Result { let ty = types.resolve(ty_id).ok_or(DecodeError::TypeIdNotFound(ty_id))?; + let ty_id = TypeId(ty_id); match ty.type_def() { - TypeDef::Composite(inner) => decode_composite_value(data, inner, types, visitor), - TypeDef::Sequence(inner) => decode_sequence_value(data, inner, types, visitor), - TypeDef::Variant(inner) => decode_variant_value(data, inner, types, visitor), - TypeDef::Array(inner) => decode_array_value(data, inner, types, visitor), - TypeDef::Tuple(inner) => decode_tuple_value(data, inner, types, visitor), - TypeDef::Primitive(inner) => decode_primitive_value(data, inner, visitor), - TypeDef::Compact(inner) => decode_compact_value(data, inner, types, visitor), - TypeDef::BitSequence(inner) => decode_bit_sequence_value(data, inner, types, visitor), + TypeDef::Composite(inner) => decode_composite_value(data, ty_id, inner, types, visitor), + TypeDef::Sequence(inner) => decode_sequence_value(data, ty_id, inner, types, visitor), + TypeDef::Variant(inner) => decode_variant_value(data, ty_id, inner, types, visitor), + TypeDef::Array(inner) => decode_array_value(data, ty_id, inner, types, visitor), + TypeDef::Tuple(inner) => decode_tuple_value(data, ty_id, inner, types, visitor), + TypeDef::Primitive(inner) => decode_primitive_value(data, ty_id, inner, visitor), + TypeDef::Compact(inner) => decode_compact_value(data, ty_id, inner, types, visitor), + TypeDef::BitSequence(inner) => { + decode_bit_sequence_value(data, ty_id, inner, types, visitor) + } } } -fn decode_composite_value<'a, V: Visitor>( - data: &mut &'a [u8], - ty: &'a TypeDefComposite, - types: &'a PortableRegistry, +fn decode_composite_value<'b, V: Visitor>( + data: &mut &[u8], + ty_id: TypeId, + ty: &'b TypeDefComposite, + types: &'b PortableRegistry, visitor: V, ) -> Result { let mut items = Composite::new(data, ty.fields(), types); - let res = visitor.visit_composite(&mut items); + let res = visitor.visit_composite(&mut items, ty_id); // Skip over any bytes that the visitor chose not to decode: items.skip_rest()?; @@ -65,10 +69,11 @@ fn decode_composite_value<'a, V: Visitor>( res } -fn decode_variant_value<'a, V: Visitor>( - data: &mut &'a [u8], - ty: &'a TypeDefVariant, - types: &'a PortableRegistry, +fn decode_variant_value<'b, V: Visitor>( + data: &mut &[u8], + ty_id: TypeId, + ty: &'b TypeDefVariant, + types: &'b PortableRegistry, visitor: V, ) -> Result { let index = *data.get(0).ok_or(DecodeError::Eof)?; @@ -83,7 +88,7 @@ fn decode_variant_value<'a, V: Visitor>( let composite = Composite::new(data, variant.fields(), types); let mut variant = Variant::new(variant, composite); - let res = visitor.visit_variant(&mut variant); + let res = visitor.visit_variant(&mut variant, ty_id); // Skip over any bytes that the visitor chose not to decode: variant.skip_rest()?; @@ -92,17 +97,18 @@ fn decode_variant_value<'a, V: Visitor>( res } -fn decode_sequence_value<'a, V: Visitor>( - data: &mut &'a [u8], - ty: &'a TypeDefSequence, - types: &'a PortableRegistry, +fn decode_sequence_value<'b, V: Visitor>( + data: &mut &[u8], + ty_id: TypeId, + ty: &'b TypeDefSequence, + types: &'b PortableRegistry, visitor: V, ) -> Result { // We assume that the sequence is preceeded by a compact encoded length, so that // we know how many values to try pulling out of the data. - let len = Compact::::decode(data).map_err(|e| e.into())?; + let len = codec::Compact::::decode(data).map_err(|e| e.into())?; let mut items = Sequence::new(data, ty.type_param().id(), len.0 as usize, types); - let res = visitor.visit_sequence(&mut items); + let res = visitor.visit_sequence(&mut items, ty_id); // Skip over any bytes that the visitor chose not to decode: items.skip_rest()?; @@ -111,16 +117,17 @@ fn decode_sequence_value<'a, V: Visitor>( res } -fn decode_array_value<'a, V: Visitor>( - data: &mut &'a [u8], - ty: &'a TypeDefArray, - types: &'a PortableRegistry, +fn decode_array_value<'b, V: Visitor>( + data: &mut &[u8], + ty_id: TypeId, + ty: &'b TypeDefArray, + types: &'b PortableRegistry, visitor: V, ) -> Result { let len = ty.len() as usize; let seq = Sequence::new(data, ty.type_param().id(), len, types); let mut arr = Array::new(seq); - let res = visitor.visit_array(&mut arr); + let res = visitor.visit_array(&mut arr, ty_id); // Skip over any bytes that the visitor chose not to decode: arr.skip_rest()?; @@ -129,14 +136,15 @@ fn decode_array_value<'a, V: Visitor>( res } -fn decode_tuple_value<'a, V: Visitor>( - data: &mut &'a [u8], - ty: &'a TypeDefTuple, - types: &'a PortableRegistry, +fn decode_tuple_value<'b, V: Visitor>( + data: &mut &[u8], + ty_id: TypeId, + ty: &'b TypeDefTuple, + types: &'b PortableRegistry, visitor: V, ) -> Result { - let mut items = Tuple::new(data, ty.fields(), types); - let res = visitor.visit_tuple(&mut items); + let mut items = Tuple::new(*data, ty.fields(), types); + let res = visitor.visit_tuple(&mut items, ty_id); // Skip over any bytes that the visitor chose not to decode: items.skip_rest()?; @@ -147,115 +155,132 @@ fn decode_tuple_value<'a, V: Visitor>( fn decode_primitive_value( data: &mut &[u8], + ty_id: TypeId, ty: &TypeDefPrimitive, visitor: V, ) -> Result { match ty { TypeDefPrimitive::Bool => { let b = bool::decode(data).map_err(|e| e.into())?; - visitor.visit_bool(b) + visitor.visit_bool(b, ty_id) } TypeDefPrimitive::Char => { // Treat chars as u32's let val = u32::decode(data).map_err(|e| e.into())?; let c = char::from_u32(val).ok_or(DecodeError::InvalidChar(val))?; - visitor.visit_char(c) + visitor.visit_char(c, ty_id) } TypeDefPrimitive::Str => { // Avoid allocating; don't decode into a String. instead, pull the bytes // and let the visitor decide whether to use them or not. let s = Str::new_from(data)?; - visitor.visit_str(&s) + visitor.visit_str(s, ty_id) } TypeDefPrimitive::U8 => { let n = u8::decode(data).map_err(|e| e.into())?; - visitor.visit_u8(n) + visitor.visit_u8(n, ty_id) } TypeDefPrimitive::U16 => { let n = u16::decode(data).map_err(|e| e.into())?; - visitor.visit_u16(n) + visitor.visit_u16(n, ty_id) } TypeDefPrimitive::U32 => { let n = u32::decode(data).map_err(|e| e.into())?; - visitor.visit_u32(n) + visitor.visit_u32(n, ty_id) } TypeDefPrimitive::U64 => { let n = u64::decode(data).map_err(|e| e.into())?; - visitor.visit_u64(n) + visitor.visit_u64(n, ty_id) } TypeDefPrimitive::U128 => { let n = u128::decode(data).map_err(|e| e.into())?; - visitor.visit_u128(n) + visitor.visit_u128(n, ty_id) } TypeDefPrimitive::U256 => { // Note; pass a reference to the visitor because this can be optimised to // take a slice of the input bytes instead of decoding to a stack value. let n = <[u8; 32]>::decode(data).map_err(|e| e.into())?; - visitor.visit_u256(&n) + visitor.visit_u256(&n, ty_id) } TypeDefPrimitive::I8 => { let n = i8::decode(data).map_err(|e| e.into())?; - visitor.visit_i8(n) + visitor.visit_i8(n, ty_id) } TypeDefPrimitive::I16 => { let n = i16::decode(data).map_err(|e| e.into())?; - visitor.visit_i16(n) + visitor.visit_i16(n, ty_id) } TypeDefPrimitive::I32 => { let n = i32::decode(data).map_err(|e| e.into())?; - visitor.visit_i32(n) + visitor.visit_i32(n, ty_id) } TypeDefPrimitive::I64 => { let n = i64::decode(data).map_err(|e| e.into())?; - visitor.visit_i64(n) + visitor.visit_i64(n, ty_id) } TypeDefPrimitive::I128 => { let n = i128::decode(data).map_err(|e| e.into())?; - visitor.visit_i128(n) + visitor.visit_i128(n, ty_id) } TypeDefPrimitive::I256 => { // Note; pass a reference to the visitor because this can be optimised to // take a slice of the input bytes instead of decoding to a stack value. let n = <[u8; 32]>::decode(data).map_err(|e| e.into())?; - visitor.visit_i256(&n) + visitor.visit_i256(&n, ty_id) } } } -fn decode_compact_value( +fn decode_compact_value<'b, V: Visitor>( data: &mut &[u8], + ty_id: TypeId, ty: &TypeDefCompact, - types: &PortableRegistry, + types: &'b PortableRegistry, visitor: V, ) -> Result { - fn decode_compact( + #[allow(clippy::too_many_arguments)] + fn decode_compact<'b, V: Visitor>( data: &mut &[u8], - inner: &scale_info::Type, - types: &PortableRegistry, + outermost_ty_id: TypeId, + current_type_id: TypeId, + mut locations: StackVec, 8>, + inner: &'b scale_info::Type, + types: &'b PortableRegistry, visitor: V, + depth: usize, ) -> Result { use TypeDefPrimitive::*; match inner.type_def() { // It's obvious how to decode basic primitive unsigned types, since we have impls for them. TypeDef::Primitive(U8) => { - let n = Compact::::decode(data).map_err(|e| e.into())?.0; - visitor.visit_compact_u8(n) + locations.push(CompactLocation::Primitive(current_type_id)); + let n = codec::Compact::::decode(data).map_err(|e| e.into())?.0; + let c = Compact::new(n, locations.as_slice()); + visitor.visit_compact_u8(c, outermost_ty_id) } TypeDef::Primitive(U16) => { - let n = Compact::::decode(data).map_err(|e| e.into())?.0; - visitor.visit_compact_u16(n) + locations.push(CompactLocation::Primitive(current_type_id)); + let n = codec::Compact::::decode(data).map_err(|e| e.into())?.0; + let c = Compact::new(n, locations.as_slice()); + visitor.visit_compact_u16(c, outermost_ty_id) } TypeDef::Primitive(U32) => { - let n = Compact::::decode(data).map_err(|e| e.into())?.0; - visitor.visit_compact_u32(n) + locations.push(CompactLocation::Primitive(current_type_id)); + let n = codec::Compact::::decode(data).map_err(|e| e.into())?.0; + let c = Compact::new(n, locations.as_slice()); + visitor.visit_compact_u32(c, outermost_ty_id) } TypeDef::Primitive(U64) => { - let n = Compact::::decode(data).map_err(|e| e.into())?.0; - visitor.visit_compact_u64(n) + locations.push(CompactLocation::Primitive(current_type_id)); + let n = codec::Compact::::decode(data).map_err(|e| e.into())?.0; + let c = Compact::new(n, locations.as_slice()); + visitor.visit_compact_u64(c, outermost_ty_id) } TypeDef::Primitive(U128) => { - let n = Compact::::decode(data).map_err(|e| e.into())?.0; - visitor.visit_compact_u128(n) + locations.push(CompactLocation::Primitive(current_type_id)); + let n = codec::Compact::::decode(data).map_err(|e| e.into())?.0; + let c = Compact::new(n, locations.as_slice()); + visitor.visit_compact_u128(c, outermost_ty_id) } // A struct with exactly 1 field containing one of the above types can be sensibly compact encoded/decoded. TypeDef::Composite(composite) => { @@ -265,6 +290,15 @@ fn decode_compact_value( // What type is the 1 field that we are able to decode? let field = &composite.fields()[0]; + + // Record this composite location. + match field.name() { + Some(name) => { + locations.push(CompactLocation::NamedComposite(current_type_id, &**name)) + } + None => locations.push(CompactLocation::UnnamedComposite(current_type_id)), + } + let field_type_id = field.ty().id(); let inner_ty = types .resolve(field_type_id) @@ -272,7 +306,16 @@ fn decode_compact_value( // Decode this inner type via compact decoding. This can recurse, in case // the inner type is also a 1-field composite type. - decode_compact(data, inner_ty, types, visitor) + decode_compact( + data, + outermost_ty_id, + TypeId(field_type_id), + locations, + inner_ty, + types, + visitor, + depth + 1, + ) } // For now, we give up if we have been asked for any other type: _cannot_decode_from => { @@ -281,15 +324,21 @@ fn decode_compact_value( } } - // Pluck the inner type out and run it through our compact decoding logic. - let inner = types - .resolve(ty.type_param().id()) - .ok_or_else(|| DecodeError::TypeIdNotFound(ty.type_param().id()))?; - decode_compact(data, inner, types, visitor) + // The type ID of the thing encoded into a Compact type. + let inner_ty_id = ty.type_param().id(); + + // Attempt to compact-decode this inner type. + let inner = types.resolve(inner_ty_id).ok_or(DecodeError::TypeIdNotFound(inner_ty_id))?; + + // Track any inner type IDs we encounter. + let locations = StackVec::::new(); + + decode_compact(data, ty_id, TypeId(inner_ty_id), locations, inner, types, visitor, 0) } fn decode_bit_sequence_value( data: &mut &[u8], + ty_id: TypeId, ty: &TypeDefBitSequence, types: &PortableRegistry, visitor: V, @@ -298,7 +347,7 @@ fn decode_bit_sequence_value( get_bitsequence_details(ty, types).map_err(DecodeError::BitSequenceError)?; let mut bitseq = BitSequence::new(store, order, data); - let res = visitor.visit_bitsequence(&mut bitseq); + let res = visitor.visit_bitsequence(&mut bitseq, ty_id); // Decode and skip over the bytes regardless of whether the visitor chooses to or not. bitseq.skip_if_not_decoded()?; diff --git a/src/lib.rs b/src/lib.rs index c17a852..04c0cee 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,18 +35,18 @@ feature(32bit_target) )] -mod bit_sequence; mod decode; +mod utils; pub mod visitor; pub use decode::decode; #[cfg(test)] mod test { - use crate::visitor::types::BitSequenceValue; + use crate::visitor::{BitSequenceValue, TypeId}; use super::*; - use codec::{Compact, Encode}; + use codec::{self, Encode}; use scale_info::PortableRegistry; /// A silly Value type for testing with a basic Visitor impl @@ -67,18 +67,35 @@ mod test { I64(i64), I128(i128), I256([u8; 32]), - CompactU8(u8), - CompactU16(u16), - CompactU32(u32), - CompactU64(u64), - CompactU128(u128), + CompactU8(Vec, u8), + CompactU16(Vec, u16), + CompactU32(Vec, u32), + CompactU64(Vec, u64), + CompactU128(Vec, u128), Sequence(Vec), - Composite(Vec<(Option, Value)>), + Composite(Vec<(String, Value)>), Tuple(Vec), Str(String), Array(Vec), - Variant(String, Vec<(Option, Value)>), - BitSequence(crate::visitor::types::BitSequenceValue), + Variant(String, Vec<(String, Value)>), + BitSequence(crate::visitor::BitSequenceValue), + } + + #[derive(Clone, Debug, PartialEq)] + enum Loc { + Unnamed, + Named(String), + Primitive, + } + + impl<'a> From> for Loc { + fn from(l: crate::visitor::CompactLocation) -> Self { + match l { + visitor::CompactLocation::UnnamedComposite(_) => Loc::Unnamed, + visitor::CompactLocation::NamedComposite(_, s) => Loc::Named(s.to_owned()), + visitor::CompactLocation::Primitive(_) => Loc::Primitive, + } + } } struct ValueVisitor; @@ -86,66 +103,100 @@ mod test { type Value = Value; type Error = crate::visitor::DecodeError; - fn visit_bool(self, value: bool) -> Result { + fn visit_bool(self, value: bool, _type_id: TypeId) -> Result { Ok(Value::Bool(value)) } - fn visit_char(self, value: char) -> Result { + fn visit_char(self, value: char, _type_id: TypeId) -> Result { Ok(Value::Char(value)) } - fn visit_u8(self, value: u8) -> Result { + fn visit_u8(self, value: u8, _type_id: TypeId) -> Result { Ok(Value::U8(value)) } - fn visit_u16(self, value: u16) -> Result { + fn visit_u16(self, value: u16, _type_id: TypeId) -> Result { Ok(Value::U16(value)) } - fn visit_u32(self, value: u32) -> Result { + fn visit_u32(self, value: u32, _type_id: TypeId) -> Result { Ok(Value::U32(value)) } - fn visit_u64(self, value: u64) -> Result { + fn visit_u64(self, value: u64, _type_id: TypeId) -> Result { Ok(Value::U64(value)) } - fn visit_u128(self, value: u128) -> Result { + fn visit_u128(self, value: u128, _type_id: TypeId) -> Result { Ok(Value::U128(value)) } - fn visit_u256(self, value: &[u8; 32]) -> Result { + fn visit_u256( + self, + value: &[u8; 32], + _type_id: TypeId, + ) -> Result { Ok(Value::U256(*value)) } - fn visit_i8(self, value: i8) -> Result { + fn visit_i8(self, value: i8, _type_id: TypeId) -> Result { Ok(Value::I8(value)) } - fn visit_i16(self, value: i16) -> Result { + fn visit_i16(self, value: i16, _type_id: TypeId) -> Result { Ok(Value::I16(value)) } - fn visit_i32(self, value: i32) -> Result { + fn visit_i32(self, value: i32, _type_id: TypeId) -> Result { Ok(Value::I32(value)) } - fn visit_i64(self, value: i64) -> Result { + fn visit_i64(self, value: i64, _type_id: TypeId) -> Result { Ok(Value::I64(value)) } - fn visit_i128(self, value: i128) -> Result { + fn visit_i128(self, value: i128, _type_id: TypeId) -> Result { Ok(Value::I128(value)) } - fn visit_i256(self, value: &[u8; 32]) -> Result { + fn visit_i256( + self, + value: &[u8; 32], + _type_id: TypeId, + ) -> Result { Ok(Value::I256(*value)) } - fn visit_compact_u8(self, value: u8) -> Result { - Ok(Value::CompactU8(value)) + fn visit_compact_u8( + self, + value: visitor::Compact, + _type_id: TypeId, + ) -> Result { + let locs = value.locations().iter().map(|&l| l.into()).collect(); + Ok(Value::CompactU8(locs, value.value())) } - fn visit_compact_u16(self, value: u16) -> Result { - Ok(Value::CompactU16(value)) + fn visit_compact_u16( + self, + value: visitor::Compact, + _type_id: TypeId, + ) -> Result { + let locs = value.locations().iter().map(|&l| l.into()).collect(); + Ok(Value::CompactU16(locs, value.value())) } - fn visit_compact_u32(self, value: u32) -> Result { - Ok(Value::CompactU32(value)) + fn visit_compact_u32( + self, + value: visitor::Compact, + _type_id: TypeId, + ) -> Result { + let locs = value.locations().iter().map(|&l| l.into()).collect(); + Ok(Value::CompactU32(locs, value.value())) } - fn visit_compact_u64(self, value: u64) -> Result { - Ok(Value::CompactU64(value)) + fn visit_compact_u64( + self, + value: visitor::Compact, + _type_id: TypeId, + ) -> Result { + let locs = value.locations().iter().map(|&l| l.into()).collect(); + Ok(Value::CompactU64(locs, value.value())) } - fn visit_compact_u128(self, value: u128) -> Result { - Ok(Value::CompactU128(value)) + fn visit_compact_u128( + self, + value: visitor::Compact, + _type_id: TypeId, + ) -> Result { + let locs = value.locations().iter().map(|&l| l.into()).collect(); + Ok(Value::CompactU128(locs, value.value())) } fn visit_sequence( self, - value: &mut visitor::types::Sequence<'_>, + value: &mut visitor::Sequence, + _type_id: TypeId, ) -> Result { let mut vals = vec![]; while let Some(val) = value.decode_item(ValueVisitor)? { @@ -155,17 +206,19 @@ mod test { } fn visit_composite( self, - value: &mut visitor::types::Composite<'_>, + value: &mut visitor::Composite, + _type_id: TypeId, ) -> Result { let mut vals = vec![]; - while let Some((name, val)) = value.decode_item(ValueVisitor)? { - vals.push((name.map(|s| s.to_owned()), val)); + while let Some((name, val)) = value.decode_item_with_name(ValueVisitor)? { + vals.push((name.to_owned(), val)); } Ok(Value::Composite(vals)) } fn visit_tuple( self, - value: &mut visitor::types::Tuple<'_>, + value: &mut visitor::Tuple, + _type_id: TypeId, ) -> Result { let mut vals = vec![]; while let Some(val) = value.decode_item(ValueVisitor)? { @@ -173,22 +226,29 @@ mod test { } Ok(Value::Tuple(vals)) } - fn visit_str(self, value: &visitor::types::Str<'_>) -> Result { + fn visit_str( + self, + value: visitor::Str, + _type_id: TypeId, + ) -> Result { Ok(Value::Str(value.as_str()?.to_owned())) } fn visit_variant( self, - value: &mut visitor::types::Variant<'_>, + value: &mut visitor::Variant, + _type_id: TypeId, ) -> Result { let mut vals = vec![]; - while let Some((name, val)) = value.decode_item(ValueVisitor)? { - vals.push((name.map(|s| s.to_owned()), val)); + let fields = value.fields(); + while let Some((name, val)) = fields.decode_item_with_name(ValueVisitor)? { + vals.push((name.to_owned(), val)); } Ok(Value::Variant(value.name().to_owned(), vals)) } fn visit_array( self, - value: &mut visitor::types::Array<'_>, + value: &mut visitor::Array, + _type_id: TypeId, ) -> Result { let mut vals = vec![]; while let Some(val) = value.decode_item(ValueVisitor)? { @@ -198,7 +258,8 @@ mod test { } fn visit_bitsequence( self, - value: &mut visitor::types::BitSequence<'_>, + value: &mut visitor::BitSequence, + _type_id: TypeId, ) -> Result { Ok(Value::BitSequence(value.decode_bitsequence()?)) } @@ -242,11 +303,11 @@ mod test { encode_decode_check(123u32, Value::U32(123)); encode_decode_check(123u64, Value::U64(123)); encode_decode_check(123u128, Value::U128(123)); - encode_decode_check(Compact(123u8), Value::CompactU8(123)); - encode_decode_check(Compact(123u16), Value::CompactU16(123)); - encode_decode_check(Compact(123u32), Value::CompactU32(123)); - encode_decode_check(Compact(123u64), Value::CompactU64(123)); - encode_decode_check(Compact(123u128), Value::CompactU128(123)); + encode_decode_check(codec::Compact(123u8), Value::CompactU8(vec![Loc::Primitive], 123)); + encode_decode_check(codec::Compact(123u16), Value::CompactU16(vec![Loc::Primitive], 123)); + encode_decode_check(codec::Compact(123u32), Value::CompactU32(vec![Loc::Primitive], 123)); + encode_decode_check(codec::Compact(123u64), Value::CompactU64(vec![Loc::Primitive], 123)); + encode_decode_check(codec::Compact(123u128), Value::CompactU128(vec![Loc::Primitive], 123)); encode_decode_check(true, Value::Bool(true)); encode_decode_check(false, Value::Bool(false)); encode_decode_check_explicit_info::('c' as u32, Value::Char('c')); @@ -261,8 +322,8 @@ mod test { struct MyWrapper { inner: u32, } - impl From> for MyWrapper { - fn from(val: Compact) -> MyWrapper { + impl From> for MyWrapper { + fn from(val: codec::Compact) -> MyWrapper { val.0 } } @@ -278,10 +339,10 @@ mod test { } encode_decode_check( - Compact(MyWrapper { inner: 123 }), + codec::Compact(MyWrapper { inner: 123 }), // Currently we ignore any composite types and just give back // the compact value directly: - Value::CompactU32(123), + Value::CompactU32(vec![Loc::Named("inner".to_owned()), Loc::Primitive], 123), ); } @@ -290,8 +351,8 @@ mod test { // A struct that can be compact encoded: #[derive(Encode, scale_info::TypeInfo)] struct MyWrapper(u32); - impl From> for MyWrapper { - fn from(val: Compact) -> MyWrapper { + impl From> for MyWrapper { + fn from(val: codec::Compact) -> MyWrapper { val.0 } } @@ -312,10 +373,10 @@ mod test { } encode_decode_check( - Compact(MyWrapper(123)), + codec::Compact(MyWrapper(123)), // Currently we ignore any composite types and just give back // the compact value directly: - Value::CompactU32(123), + Value::CompactU32(vec![Loc::Unnamed, Loc::Primitive], 123), ); } @@ -345,15 +406,15 @@ mod test { encode_decode_check( MyEnum::Foo(true), - Value::Variant("Foo".to_owned(), vec![(None, Value::Bool(true))]), + Value::Variant("Foo".to_owned(), vec![(String::new(), Value::Bool(true))]), ); encode_decode_check( MyEnum::Bar { hi: "hello".to_string(), other: 123 }, Value::Variant( "Bar".to_owned(), vec![ - (Some("hi".to_string()), Value::Str("hello".to_string())), - (Some("other".to_string()), Value::U128(123)), + ("hi".to_string(), Value::Str("hello".to_string())), + ("other".to_string(), Value::U128(123)), ], ), ); @@ -374,18 +435,18 @@ mod test { encode_decode_check( Unnamed(true, "James".into(), vec![1, 2, 3]), Value::Composite(vec![ - (None, Value::Bool(true)), - (None, Value::Str("James".to_string())), - (None, Value::Sequence(vec![Value::U8(1), Value::U8(2), Value::U8(3)])), + (String::new(), Value::Bool(true)), + (String::new(), Value::Str("James".to_string())), + (String::new(), Value::Sequence(vec![Value::U8(1), Value::U8(2), Value::U8(3)])), ]), ); encode_decode_check( Named { is_valid: true, name: "James".into(), bytes: vec![1, 2, 3] }, Value::Composite(vec![ - (Some("is_valid".to_string()), Value::Bool(true)), - (Some("name".to_string()), Value::Str("James".to_string())), + ("is_valid".to_string(), Value::Bool(true)), + ("name".to_string(), Value::Str("James".to_string())), ( - Some("bytes".to_string()), + "bytes".to_string(), Value::Sequence(vec![Value::U8(1), Value::U8(2), Value::U8(3)]), ), ]), diff --git a/src/bit_sequence.rs b/src/utils/bit_sequence.rs similarity index 100% rename from src/bit_sequence.rs rename to src/utils/bit_sequence.rs diff --git a/src/utils/mod.rs b/src/utils/mod.rs new file mode 100644 index 0000000..b201c49 --- /dev/null +++ b/src/utils/mod.rs @@ -0,0 +1,17 @@ +// Copyright (C) 2022 Parity Technologies (UK) Ltd. (admin@parity.io) +// This file is a part of the scale-value crate. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +pub mod bit_sequence; +pub mod stack_vec; diff --git a/src/utils/stack_vec.rs b/src/utils/stack_vec.rs new file mode 100644 index 0000000..9b6a920 --- /dev/null +++ b/src/utils/stack_vec.rs @@ -0,0 +1,97 @@ +// Copyright (C) 2022 Parity Technologies (UK) Ltd. (admin@parity.io) +// This file is a part of the scale-value crate. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/// A quick hopefully-stack-only vec implementation for holding TypeIds. +pub struct StackVec { + inner: StackVecInner, +} + +enum StackVecInner { + Stack { len: usize, items: [T; N] }, + Heap { items: Vec }, +} + +impl StackVec { + pub fn new() -> Self { + StackVec { inner: StackVecInner::Stack { len: 0, items: [Default::default(); N] } } + } + pub fn as_slice(&self) -> &[T] { + match &self.inner { + StackVecInner::Stack { len, items } => &items[0..*len], + StackVecInner::Heap { items } => items, + } + } + pub fn push(&mut self, item: T) { + match &mut self.inner { + StackVecInner::Heap { items } => items.push(item), + StackVecInner::Stack { len, items } => { + if *len == N { + let mut v = items[0..*len].to_vec(); + v.push(item); + self.inner = StackVecInner::Heap { items: v }; + } else { + items[*len] = item; + *len += 1; + } + } + } + } + #[cfg(test)] + pub fn is_heap(&self) -> bool { + match self.inner { + StackVecInner::Stack { .. } => false, + StackVecInner::Heap { .. } => true, + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn doesnt_overflow() { + let mut s = StackVec::<_, 4>::new(); + + assert_eq!(s.as_slice(), &[]); + assert!(!s.is_heap()); + + s.push(1); + assert_eq!(s.as_slice(), &[1]); + assert!(!s.is_heap()); + + s.push(2); + assert_eq!(s.as_slice(), &[1, 2]); + assert!(!s.is_heap()); + + s.push(3); + assert_eq!(s.as_slice(), &[1, 2, 3]); + assert!(!s.is_heap()); + + s.push(4); + assert_eq!(s.as_slice(), &[1, 2, 3, 4]); + assert!(!s.is_heap()); + + // Allocates on the heap after 4 items pushed.. + + s.push(5); + assert_eq!(s.as_slice(), &[1, 2, 3, 4, 5]); + assert!(s.is_heap()); + + s.push(6); + assert_eq!(s.as_slice(), &[1, 2, 3, 4, 5, 6]); + assert!(s.is_heap()); + } +} diff --git a/src/visitor/array.rs b/src/visitor/array.rs index b847a96..054d7a5 100644 --- a/src/visitor/array.rs +++ b/src/visitor/array.rs @@ -16,12 +16,12 @@ use super::{sequence::Sequence, DecodeError, Visitor}; /// This represents an array type. -pub struct Array<'a> { - seq: Sequence<'a>, +pub struct Array<'a, 'b> { + seq: Sequence<'a, 'b>, } -impl<'a> Array<'a> { - pub(crate) fn new(seq: Sequence<'a>) -> Self { +impl<'a, 'b> Array<'a, 'b> { + pub(crate) fn new(seq: Sequence<'a, 'b>) -> Self { Array { seq } } pub(crate) fn bytes(&self) -> &'a [u8] { diff --git a/src/visitor/bit_sequence.rs b/src/visitor/bit_sequence.rs index a5ccf6f..1b0db25 100644 --- a/src/visitor/bit_sequence.rs +++ b/src/visitor/bit_sequence.rs @@ -14,7 +14,7 @@ // limitations under the License. use super::DecodeError; -use crate::bit_sequence::{BitOrderTy, BitStoreTy}; +use crate::utils::bit_sequence::{BitOrderTy, BitStoreTy}; use bitvec::{ order::{Lsb0, Msb0}, vec::BitVec, @@ -82,7 +82,7 @@ impl<'a> BitSequence<'a> { #[cfg(feature = "32bit_target")] (BitStoreTy::U64, _) => { return Err(DecodeError::BitSequenceError( - crate::bit_sequence::BitSequenceError::StoreTypeNotSupported( + crate::utils::bit_sequence::BitSequenceError::StoreTypeNotSupported( "u64 (pointer-width on this compile target is not 64)".into(), ), )) @@ -132,6 +132,23 @@ pub enum BitSequenceValue { U64Msb0(BitVec), } +impl BitSequenceValue { + /// Convert whatever bit sequence is returned to one with a store type of `u8` + /// and an order type of `Lsb0`. + pub fn to_u8_lsb0(self) -> BitVec { + match self { + BitSequenceValue::U8Lsb0(b) => b, + BitSequenceValue::U8Msb0(b) => b.iter().by_vals().collect(), + BitSequenceValue::U16Lsb0(b) => b.iter().by_vals().collect(), + BitSequenceValue::U16Msb0(b) => b.iter().by_vals().collect(), + BitSequenceValue::U32Lsb0(b) => b.iter().by_vals().collect(), + BitSequenceValue::U32Msb0(b) => b.iter().by_vals().collect(), + BitSequenceValue::U64Lsb0(b) => b.iter().by_vals().collect(), + BitSequenceValue::U64Msb0(b) => b.iter().by_vals().collect(), + } + } +} + #[cfg(test)] mod test { use super::*; diff --git a/src/visitor/compact.rs b/src/visitor/compact.rs new file mode 100644 index 0000000..d73c192 --- /dev/null +++ b/src/visitor/compact.rs @@ -0,0 +1,68 @@ +// Copyright (C) 2022 Parity Technologies (UK) Ltd. (admin@parity.io) +// This file is a part of the scale-value crate. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::TypeId; + +/// This represents a compact encoded type. +pub struct Compact<'b, 'c, T> { + val: T, + locations: &'c [CompactLocation<'b>], +} + +impl<'b, 'c, T: Copy> Compact<'b, 'c, T> { + pub(crate) fn new(val: T, locations: &'c [CompactLocation<'b>]) -> Compact<'b, 'c, T> { + Compact { val, locations } + } + /// Return the value that was compact-encoded + pub fn value(&self) -> T { + self.val + } + /// Compact values can be nested inside named or unnamed fields in structs. + /// This provides back a slice of + pub fn locations(&self) -> &'c [CompactLocation<'b>] { + self.locations + } +} + +/// A pointer to what the compact value is contained within. +#[derive(Clone, Copy, Debug)] +pub enum CompactLocation<'b> { + /// We're in an unnamed composite (struct) with the type ID given. + UnnamedComposite(TypeId), + /// We're in a named composite (struct) with the type ID given, and the compact + /// value lives inside the field with the given name. + NamedComposite(TypeId, &'b str), + /// We're at a primitive type with the type ID given; the compact value itself. + Primitive(TypeId), +} + +impl<'b> CompactLocation<'b> { + /// Return the Primitive type of this location, if one exists. + pub fn as_primitive(self) -> Option { + match self { + CompactLocation::Primitive(t) => Some(t), + _ => None, + } + } +} + +// Default values for locations are never handed back, but they are +// stored on the StackArray in the "unused" positions. We could avoid needing +// this with some unsafe code. +impl<'a> Default for CompactLocation<'a> { + fn default() -> Self { + CompactLocation::Primitive(TypeId::default()) + } +} diff --git a/src/visitor/composite.rs b/src/visitor/composite.rs index c6b77d3..d54ba65 100644 --- a/src/visitor/composite.rs +++ b/src/visitor/composite.rs @@ -17,18 +17,18 @@ use super::{DecodeError, IgnoreVisitor, Visitor}; use scale_info::{form::PortableForm, Field, PortableRegistry}; /// This represents a composite type. -pub struct Composite<'a> { +pub struct Composite<'a, 'b> { bytes: &'a [u8], - fields: &'a [Field], - types: &'a PortableRegistry, + fields: &'b [Field], + types: &'b PortableRegistry, } -impl<'a> Composite<'a> { +impl<'a, 'b> Composite<'a, 'b> { pub(crate) fn new( bytes: &'a [u8], - fields: &'a [Field], - types: &'a PortableRegistry, - ) -> Composite<'a> { + fields: &'b [Field], + types: &'b PortableRegistry, + ) -> Composite<'a, 'b> { Composite { bytes, fields, types } } pub(crate) fn bytes(&self) -> &'a [u8] { @@ -40,25 +40,27 @@ impl<'a> Composite<'a> { } Ok(()) } - /// The number of un-decoded items remaining in this composite type. - pub fn len(&self) -> usize { - self.fields.len() + /// Do any of the fields in this composite type have names? Either all of them + /// should be named, or none of them should be. + pub fn fields(&self) -> &'b [Field] { + self.fields } - /// Are there any un-decoded items remaining in this composite type. - pub fn is_empty(&self) -> bool { - self.fields.is_empty() + /// Decode the next field in the composite type by providing a visitor to handle it. + pub fn decode_item(&mut self, visitor: V) -> Result, V::Error> { + self.decode_item_with_name(visitor).map(|o| o.map(|(_n, v)| v)) } /// Decode the next field in the composite type by providing a visitor to handle it. - pub fn decode_item( + /// The name of the field will be returned too, or an empty string if it doesn't exist. + pub fn decode_item_with_name( &mut self, visitor: V, - ) -> Result>, V::Error> { + ) -> Result, V::Error> { if self.fields.is_empty() { return Ok(None); } let field = &self.fields[0]; - let field_name = self.fields.get(0).and_then(|f| f.name().map(|n| &**n)); + let field_name = self.fields.get(0).and_then(|f| f.name().map(|n| &**n)).unwrap_or(""); let b = &mut self.bytes; // Don't return here; decrement bytes properly first and then return, so that @@ -71,6 +73,3 @@ impl<'a> Composite<'a> { res.map(|val| Some((field_name, val))) } } - -/// A tuple of a name for the field (which may or may not exist) and a value. -pub type CompositeValue<'a, Value> = (Option<&'a str>, Value); diff --git a/src/visitor/mod.rs b/src/visitor/mod.rs index 1ebc59c..bd90b5f 100644 --- a/src/visitor/mod.rs +++ b/src/visitor/mod.rs @@ -17,26 +17,24 @@ mod array; mod bit_sequence; +mod compact; mod composite; mod sequence; mod str; mod tuple; mod variant; -use crate::bit_sequence::BitSequenceError; +use crate::utils::bit_sequence::BitSequenceError; use scale_info::form::PortableForm; -/// Types used in the [`Visitor`] trait to represent different things -/// that can be decoded from the input. -pub mod types { - pub use super::array::Array; - pub use super::bit_sequence::{BitSequence, BitSequenceValue}; - pub use super::composite::{Composite, CompositeValue}; - pub use super::sequence::Sequence; - pub use super::str::Str; - pub use super::tuple::Tuple; - pub use super::variant::Variant; -} +pub use self::str::Str; +pub use array::Array; +pub use bit_sequence::{BitSequence, BitSequenceValue}; +pub use compact::{Compact, CompactLocation}; +pub use composite::Composite; +pub use sequence::Sequence; +pub use tuple::Tuple; +pub use variant::Variant; /// An implementation of the [`Visitor`] trait can be passed to the [`crate::decode()`] /// function, and is handed back values as they are encountered. It's up to the implementation @@ -49,49 +47,62 @@ pub trait Visitor: Sized { type Error: From; /// Called when a bool is seen in the input bytes. - fn visit_bool(self, value: bool) -> Result; + fn visit_bool(self, value: bool, type_id: TypeId) -> Result; /// Called when a bool is seen in the input bytes. - fn visit_char(self, value: char) -> Result; + fn visit_char(self, value: char, type_id: TypeId) -> Result; /// Called when a u8 is seen in the input bytes. - fn visit_u8(self, value: u8) -> Result; + fn visit_u8(self, value: u8, type_id: TypeId) -> Result; /// Called when a u16 is seen in the input bytes. - fn visit_u16(self, value: u16) -> Result; + fn visit_u16(self, value: u16, type_id: TypeId) -> Result; /// Called when a u32 is seen in the input bytes. - fn visit_u32(self, value: u32) -> Result; + fn visit_u32(self, value: u32, type_id: TypeId) -> Result; /// Called when a u64 is seen in the input bytes. - fn visit_u64(self, value: u64) -> Result; + fn visit_u64(self, value: u64, type_id: TypeId) -> Result; /// Called when a u128 is seen in the input bytes. - fn visit_u128(self, value: u128) -> Result; + fn visit_u128(self, value: u128, type_id: TypeId) -> Result; /// Called when a u256 is seen in the input bytes. - fn visit_u256(self, value: &[u8; 32]) -> Result; + fn visit_u256(self, value: &[u8; 32], type_id: TypeId) -> Result; /// Called when an i8 is seen in the input bytes. - fn visit_i8(self, value: i8) -> Result; + fn visit_i8(self, value: i8, type_id: TypeId) -> Result; /// Called when an i16 is seen in the input bytes. - fn visit_i16(self, value: i16) -> Result; + fn visit_i16(self, value: i16, type_id: TypeId) -> Result; /// Called when an i32 is seen in the input bytes. - fn visit_i32(self, value: i32) -> Result; + fn visit_i32(self, value: i32, type_id: TypeId) -> Result; /// Called when an i64 is seen in the input bytes. - fn visit_i64(self, value: i64) -> Result; + fn visit_i64(self, value: i64, type_id: TypeId) -> Result; /// Called when an i128 is seen in the input bytes. - fn visit_i128(self, value: i128) -> Result; + fn visit_i128(self, value: i128, type_id: TypeId) -> Result; /// Called when an i256 is seen in the input bytes. - fn visit_i256(self, value: &[u8; 32]) -> Result; + fn visit_i256(self, value: &[u8; 32], type_id: TypeId) -> Result; /// Called when a sequence of values is seen in the input bytes. - fn visit_sequence(self, value: &mut types::Sequence<'_>) -> Result; + fn visit_sequence( + self, + value: &mut Sequence, + type_id: TypeId, + ) -> Result; /// Called when a composite value is seen in the input bytes. - fn visit_composite(self, value: &mut types::Composite<'_>) -> Result; + fn visit_composite( + self, + value: &mut Composite, + type_id: TypeId, + ) -> Result; /// Called when a tuple of values is seen in the input bytes. - fn visit_tuple(self, value: &mut types::Tuple<'_>) -> Result; + fn visit_tuple(self, value: &mut Tuple, type_id: TypeId) -> Result; /// Called when a string value is seen in the input bytes. - fn visit_str(self, value: &types::Str<'_>) -> Result; + fn visit_str(self, value: Str, type_id: TypeId) -> Result; /// Called when a variant is seen in the input bytes. - fn visit_variant(self, value: &mut types::Variant<'_>) -> Result; + fn visit_variant( + self, + value: &mut Variant, + type_id: TypeId, + ) -> Result; /// Called when an array is seen in the input bytes. - fn visit_array(self, value: &mut types::Array<'_>) -> Result; + fn visit_array(self, value: &mut Array, type_id: TypeId) -> Result; /// Called when a bit sequence is seen in the input bytes. fn visit_bitsequence( self, - value: &mut types::BitSequence<'_>, + value: &mut BitSequence, + type_id: TypeId, ) -> Result; // Default implementations for visiting compact values just delegate and @@ -99,24 +110,44 @@ pub trait Visitor: Sized { // that the thing was compact encoded: /// Called when a compact encoded u8 is seen in the input bytes. - fn visit_compact_u8(self, value: u8) -> Result { - self.visit_u8(value) + fn visit_compact_u8( + self, + value: Compact, + type_id: TypeId, + ) -> Result { + self.visit_u8(value.value(), type_id) } /// Called when a compact encoded u16 is seen in the input bytes. - fn visit_compact_u16(self, value: u16) -> Result { - self.visit_u16(value) + fn visit_compact_u16( + self, + value: Compact, + type_id: TypeId, + ) -> Result { + self.visit_u16(value.value(), type_id) } /// Called when a compact encoded u32 is seen in the input bytes. - fn visit_compact_u32(self, value: u32) -> Result { - self.visit_u32(value) + fn visit_compact_u32( + self, + value: Compact, + type_id: TypeId, + ) -> Result { + self.visit_u32(value.value(), type_id) } /// Called when a compact encoded u64 is seen in the input bytes. - fn visit_compact_u64(self, value: u64) -> Result { - self.visit_u64(value) + fn visit_compact_u64( + self, + value: Compact, + type_id: TypeId, + ) -> Result { + self.visit_u64(value.value(), type_id) } /// Called when a compact encoded u128 is seen in the input bytes. - fn visit_compact_u128(self, value: u128) -> Result { - self.visit_u128(value) + fn visit_compact_u128( + self, + value: Compact, + type_id: TypeId, + ) -> Result { + self.visit_u128(value.value(), type_id) } } @@ -152,6 +183,10 @@ pub enum DecodeError { NothingLeftToDecode, } +/// The ID of the type being decoded. +#[derive(Clone, Copy, Debug, Default)] +pub struct TypeId(pub u32); + /// A [`Visitor`] implementation that just ignores all of the bytes. pub struct IgnoreVisitor; @@ -159,72 +194,82 @@ impl Visitor for IgnoreVisitor { type Value = (); type Error = DecodeError; - fn visit_bool(self, _value: bool) -> Result { + fn visit_bool(self, _value: bool, _type_id: TypeId) -> Result { Ok(()) } - fn visit_char(self, _value: char) -> Result { + fn visit_char(self, _value: char, _type_id: TypeId) -> Result { Ok(()) } - fn visit_u8(self, _value: u8) -> Result { + fn visit_u8(self, _value: u8, _type_id: TypeId) -> Result { Ok(()) } - fn visit_u16(self, _value: u16) -> Result { + fn visit_u16(self, _value: u16, _type_id: TypeId) -> Result { Ok(()) } - fn visit_u32(self, _value: u32) -> Result { + fn visit_u32(self, _value: u32, _type_id: TypeId) -> Result { Ok(()) } - fn visit_u64(self, _value: u64) -> Result { + fn visit_u64(self, _value: u64, _type_id: TypeId) -> Result { Ok(()) } - fn visit_u128(self, _value: u128) -> Result { + fn visit_u128(self, _value: u128, _type_id: TypeId) -> Result { Ok(()) } - fn visit_u256(self, _value: &[u8; 32]) -> Result { + fn visit_u256(self, _value: &[u8; 32], _type_id: TypeId) -> Result { Ok(()) } - fn visit_i8(self, _value: i8) -> Result { + fn visit_i8(self, _value: i8, _type_id: TypeId) -> Result { Ok(()) } - fn visit_i16(self, _value: i16) -> Result { + fn visit_i16(self, _value: i16, _type_id: TypeId) -> Result { Ok(()) } - fn visit_i32(self, _value: i32) -> Result { + fn visit_i32(self, _value: i32, _type_id: TypeId) -> Result { Ok(()) } - fn visit_i64(self, _value: i64) -> Result { + fn visit_i64(self, _value: i64, _type_id: TypeId) -> Result { Ok(()) } - fn visit_i128(self, _value: i128) -> Result { + fn visit_i128(self, _value: i128, _type_id: TypeId) -> Result { Ok(()) } - fn visit_i256(self, _value: &[u8; 32]) -> Result { + fn visit_i256(self, _value: &[u8; 32], _type_id: TypeId) -> Result { Ok(()) } - fn visit_sequence(self, _value: &mut types::Sequence<'_>) -> Result { + fn visit_sequence( + self, + _value: &mut Sequence, + _type_id: TypeId, + ) -> Result { Ok(()) } fn visit_composite( self, - _value: &mut types::Composite<'_>, + _value: &mut Composite, + _type_id: TypeId, ) -> Result { Ok(()) } - fn visit_tuple(self, _value: &mut types::Tuple<'_>) -> Result { + fn visit_tuple(self, _value: &mut Tuple, _type_id: TypeId) -> Result { Ok(()) } - fn visit_str(self, _value: &types::Str<'_>) -> Result { + fn visit_str(self, _value: Str, _type_id: TypeId) -> Result { Ok(()) } - fn visit_array(self, _value: &mut types::Array<'_>) -> Result { + fn visit_array(self, _value: &mut Array, _type_id: TypeId) -> Result { Ok(()) } - fn visit_variant(self, _value: &mut types::Variant<'_>) -> Result { + fn visit_variant( + self, + _value: &mut Variant, + _type_id: TypeId, + ) -> Result { Ok(()) } fn visit_bitsequence( self, - _value: &mut types::BitSequence<'_>, + _value: &mut BitSequence, + _type_id: TypeId, ) -> Result { Ok(()) } diff --git a/src/visitor/sequence.rs b/src/visitor/sequence.rs index c55728b..bffb150 100644 --- a/src/visitor/sequence.rs +++ b/src/visitor/sequence.rs @@ -17,20 +17,20 @@ use super::{DecodeError, IgnoreVisitor, Visitor}; use scale_info::PortableRegistry; /// This enables a visitor to decode items from a sequence type. -pub struct Sequence<'a> { +pub struct Sequence<'a, 'b> { bytes: &'a [u8], type_id: u32, - types: &'a PortableRegistry, + types: &'b PortableRegistry, remaining: usize, } -impl<'a> Sequence<'a> { +impl<'a, 'b> Sequence<'a, 'b> { pub(crate) fn new( bytes: &'a [u8], type_id: u32, len: usize, - types: &'a PortableRegistry, - ) -> Sequence<'a> { + types: &'b PortableRegistry, + ) -> Sequence<'a, 'b> { Sequence { bytes, type_id, types, remaining: len } } pub(crate) fn bytes(&self) -> &'a [u8] { diff --git a/src/visitor/tuple.rs b/src/visitor/tuple.rs index 877ac40..246212d 100644 --- a/src/visitor/tuple.rs +++ b/src/visitor/tuple.rs @@ -17,18 +17,18 @@ use super::{DecodeError, IgnoreVisitor, Visitor}; use scale_info::PortableRegistry; /// This represents a tuple of values. -pub struct Tuple<'a> { +pub struct Tuple<'a, 'b> { bytes: &'a [u8], - fields: &'a [scale_info::interner::UntrackedSymbol], - types: &'a PortableRegistry, + fields: &'b [scale_info::interner::UntrackedSymbol], + types: &'b PortableRegistry, } -impl<'a> Tuple<'a> { +impl<'a, 'b> Tuple<'a, 'b> { pub(crate) fn new( bytes: &'a [u8], - fields: &'a [scale_info::interner::UntrackedSymbol], - types: &'a PortableRegistry, - ) -> Tuple<'a> { + fields: &'b [scale_info::interner::UntrackedSymbol], + types: &'b PortableRegistry, + ) -> Tuple<'a, 'b> { Tuple { bytes, fields, types } } pub(crate) fn bytes(&self) -> &'a [u8] { diff --git a/src/visitor/variant.rs b/src/visitor/variant.rs index 596ebcb..e400f0b 100644 --- a/src/visitor/variant.rs +++ b/src/visitor/variant.rs @@ -13,20 +13,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -use super::{composite::Composite, DecodeError, Visitor}; +use super::{composite::Composite, DecodeError}; use scale_info::form::PortableForm; /// A representation of the a variant type. -pub struct Variant<'a> { - variant: &'a scale_info::Variant, - fields: Composite<'a>, +pub struct Variant<'a, 'b> { + variant: &'b scale_info::Variant, + fields: Composite<'a, 'b>, } -impl<'a> Variant<'a> { +impl<'a, 'b> Variant<'a, 'b> { pub(crate) fn new( - variant: &'a scale_info::Variant, - fields: Composite<'a>, - ) -> Variant<'a> { + variant: &'b scale_info::Variant, + fields: Composite<'a, 'b>, + ) -> Variant<'a, 'b> { Variant { variant, fields } } pub(crate) fn bytes(&self) -> &'a [u8] { @@ -43,19 +43,8 @@ impl<'a> Variant<'a> { pub fn index(&self) -> u8 { self.variant.index() } - /// The number of un-decoded fields in the variant. - pub fn len(&self) -> usize { - self.fields.len() - } - /// Are there any un-decoded fields remaining in the variant. - pub fn is_empty(&self) -> bool { - self.fields.is_empty() - } - /// Decode the next field in the variant by providing a visitor to handle it. - pub fn decode_item( - &mut self, - visitor: V, - ) -> Result>, V::Error> { - self.fields.decode_item(visitor) + /// Access the variant fields. + pub fn fields(&mut self) -> &mut Composite<'a, 'b> { + &mut self.fields } }