diff --git a/CODEOWNERS b/CODEOWNERS index 4af6a28..4414e09 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,5 +1,5 @@ -# main codeowner @paritytech/tools-team -* @paritytech/tools-team +# main codeowner @paritytech/subxt-team +* @paritytech/subxt-team # CI -/.github/ @paritytech/ci @paritytech/tools-team \ No newline at end of file +/.github/ @paritytech/ci @paritytech/subxt-team \ No newline at end of file diff --git a/scale-decode-derive/src/lib.rs b/scale-decode-derive/src/lib.rs index ebfb3e6..8507a1b 100644 --- a/scale-decode-derive/src/lib.rs +++ b/scale-decode-derive/src/lib.rs @@ -17,7 +17,7 @@ extern crate alloc; use alloc::string::ToString; use darling::FromAttributes; -use proc_macro2::TokenStream as TokenStream2; +use proc_macro2::{Span, TokenStream as TokenStream2}; use quote::quote; use syn::{parse_macro_input, punctuated::Punctuated, DeriveInput}; @@ -59,10 +59,17 @@ fn generate_enum_impl( ) -> TokenStream2 { let path_to_scale_decode = &attrs.crate_path; let path_to_type: syn::Path = input.ident.clone().into(); - let (impl_generics, ty_generics, where_clause, phantomdata_type) = - handle_generics(&attrs, &input.generics); let variant_names = details.variants.iter().map(|v| v.ident.to_string()); + let generic_types = handle_generics(&attrs, input.generics.clone()); + let ty_generics = generic_types.ty_generics(); + let impl_generics = generic_types.impl_generics(); + let visitor_where_clause = generic_types.visitor_where_clause(); + let visitor_ty_generics = generic_types.visitor_ty_generics(); + let visitor_impl_generics = generic_types.visitor_impl_generics(); + let visitor_phantomdata_type = generic_types.visitor_phantomdata_type(); + let type_resolver_ident = generic_types.type_resolver_ident(); + // determine what the body of our visitor functions will be based on the type of enum fields // that we're trying to generate output for. let variant_ifs = details.variants.iter().map(|variant| { @@ -130,28 +137,29 @@ fn generate_enum_impl( quote!( const _: () = { - #visibility struct Visitor #impl_generics ( - ::core::marker::PhantomData<#phantomdata_type> + #visibility struct Visitor #visitor_impl_generics ( + ::core::marker::PhantomData<#visitor_phantomdata_type> ); use #path_to_scale_decode::vec; use #path_to_scale_decode::ToString; - impl #impl_generics #path_to_scale_decode::IntoVisitor for #path_to_type #ty_generics #where_clause { - type Visitor = Visitor #ty_generics; - fn into_visitor() -> Self::Visitor { + impl #impl_generics #path_to_scale_decode::IntoVisitor for #path_to_type #ty_generics #visitor_where_clause { + type AnyVisitor<#type_resolver_ident: #path_to_scale_decode::TypeResolver> = Visitor #visitor_ty_generics; + fn into_visitor<#type_resolver_ident: #path_to_scale_decode::TypeResolver>() -> Self::AnyVisitor<#type_resolver_ident> { Visitor(::core::marker::PhantomData) } } - impl #impl_generics #path_to_scale_decode::Visitor for Visitor #ty_generics #where_clause { + impl #visitor_impl_generics #path_to_scale_decode::Visitor for Visitor #visitor_ty_generics #visitor_where_clause { type Error = #path_to_scale_decode::Error; type Value<'scale, 'info> = #path_to_type #ty_generics; + type TypeResolver = #type_resolver_ident; fn visit_variant<'scale, 'info>( self, - value: &mut #path_to_scale_decode::visitor::types::Variant<'scale, 'info>, - type_id: #path_to_scale_decode::visitor::TypeId, + value: &mut #path_to_scale_decode::visitor::types::Variant<'scale, 'info, Self::TypeResolver>, + type_id: &::TypeId, ) -> Result, Self::Error> { #( #variant_ifs @@ -164,8 +172,8 @@ fn generate_enum_impl( // Allow an enum to be decoded through nested 1-field composites and tuples: fn visit_composite<'scale, 'info>( self, - value: &mut #path_to_scale_decode::visitor::types::Composite<'scale, 'info>, - _type_id: #path_to_scale_decode::visitor::TypeId, + value: &mut #path_to_scale_decode::visitor::types::Composite<'scale, 'info, Self::TypeResolver>, + _type_id: &::TypeId, ) -> Result, Self::Error> { if value.remaining() != 1 { return self.visit_unexpected(#path_to_scale_decode::visitor::Unexpected::Composite); @@ -174,8 +182,8 @@ fn generate_enum_impl( } fn visit_tuple<'scale, 'info>( self, - value: &mut #path_to_scale_decode::visitor::types::Tuple<'scale, 'info>, - _type_id: #path_to_scale_decode::visitor::TypeId, + value: &mut #path_to_scale_decode::visitor::types::Tuple<'scale, 'info, Self::TypeResolver>, + _type_id: &::TypeId, ) -> Result, Self::Error> { if value.remaining() != 1 { return self.visit_unexpected(#path_to_scale_decode::visitor::Unexpected::Tuple); @@ -195,8 +203,15 @@ fn generate_struct_impl( ) -> TokenStream2 { let path_to_scale_decode = &attrs.crate_path; let path_to_type: syn::Path = input.ident.clone().into(); - let (impl_generics, ty_generics, where_clause, phantomdata_type) = - handle_generics(&attrs, &input.generics); + + let generic_types = handle_generics(&attrs, input.generics.clone()); + let ty_generics = generic_types.ty_generics(); + let impl_generics = generic_types.impl_generics(); + let visitor_where_clause = generic_types.visitor_where_clause(); + let visitor_ty_generics = generic_types.visitor_ty_generics(); + let visitor_impl_generics = generic_types.visitor_impl_generics(); + let visitor_phantomdata_type = generic_types.visitor_phantomdata_type(); + let type_resolver_ident = generic_types.type_resolver_ident(); // determine what the body of our visitor functions will be based on the type of struct // that we're trying to generate output for. @@ -260,48 +275,51 @@ fn generate_struct_impl( quote!( const _: () = { - #visibility struct Visitor #impl_generics ( - ::core::marker::PhantomData<#phantomdata_type> + #visibility struct Visitor #visitor_impl_generics ( + ::core::marker::PhantomData<#visitor_phantomdata_type> ); use #path_to_scale_decode::vec; use #path_to_scale_decode::ToString; - impl #impl_generics #path_to_scale_decode::IntoVisitor for #path_to_type #ty_generics #where_clause { - type Visitor = Visitor #ty_generics; - fn into_visitor() -> Self::Visitor { + impl #impl_generics #path_to_scale_decode::IntoVisitor for #path_to_type #ty_generics #visitor_where_clause { + type AnyVisitor<#type_resolver_ident: #path_to_scale_decode::TypeResolver> = Visitor #visitor_ty_generics; + fn into_visitor<#type_resolver_ident: #path_to_scale_decode::TypeResolver>() -> Self::AnyVisitor<#type_resolver_ident> { Visitor(::core::marker::PhantomData) } } - impl #impl_generics #path_to_scale_decode::Visitor for Visitor #ty_generics #where_clause { + impl #visitor_impl_generics #path_to_scale_decode::Visitor for Visitor #visitor_ty_generics #visitor_where_clause { type Error = #path_to_scale_decode::Error; type Value<'scale, 'info> = #path_to_type #ty_generics; + type TypeResolver = #type_resolver_ident; fn visit_composite<'scale, 'info>( self, - value: &mut #path_to_scale_decode::visitor::types::Composite<'scale, 'info>, - type_id: #path_to_scale_decode::visitor::TypeId, + value: &mut #path_to_scale_decode::visitor::types::Composite<'scale, 'info, Self::TypeResolver>, + type_id: &::TypeId, ) -> Result, Self::Error> { #visit_composite_body } fn visit_tuple<'scale, 'info>( self, - value: &mut #path_to_scale_decode::visitor::types::Tuple<'scale, 'info>, - type_id: #path_to_scale_decode::visitor::TypeId, + value: &mut #path_to_scale_decode::visitor::types::Tuple<'scale, 'info, Self::TypeResolver>, + type_id: &::TypeId, ) -> Result, Self::Error> { #visit_tuple_body } } - impl #impl_generics #path_to_scale_decode::DecodeAsFields for #path_to_type #ty_generics #where_clause { - fn decode_as_fields<'info>(input: &mut &[u8], fields: &mut dyn #path_to_scale_decode::FieldIter<'info>, types: &'info #path_to_scale_decode::PortableRegistry) - -> Result + impl #impl_generics #path_to_scale_decode::DecodeAsFields for #path_to_type #ty_generics #visitor_where_clause { + fn decode_as_fields<'info, R: #path_to_scale_decode::TypeResolver>( + input: &mut &[u8], + fields: &mut dyn #path_to_scale_decode::FieldIter<'info, R::TypeId>, + types: &'info R + ) -> Result { - let path = #path_to_scale_decode::EMPTY_SCALE_INFO_PATH; - let mut composite = #path_to_scale_decode::visitor::types::Composite::new(input, path, fields, types, false); + let mut composite = #path_to_scale_decode::visitor::types::Composite::new(input, fields, types, false); use #path_to_scale_decode::{ Visitor, IntoVisitor }; - let val = <#path_to_type #ty_generics>::into_visitor().visit_composite(&mut composite, #path_to_scale_decode::visitor::TypeId(0)); + let val = <#path_to_type #ty_generics>::into_visitor().visit_composite(&mut composite, &Default::default()); // Consume any remaining bytes and update input: composite.skip_decoding()?; @@ -392,29 +410,31 @@ fn unnamed_field_vals<'f>( (field_count, field_vals) } -fn handle_generics<'a>( - attrs: &TopLevelAttrs, - generics: &'a syn::Generics, -) -> (syn::ImplGenerics<'a>, syn::TypeGenerics<'a>, syn::WhereClause, syn::Type) { +fn handle_generics(attrs: &TopLevelAttrs, generics: syn::Generics) -> GenericTypes { let path_to_crate = &attrs.crate_path; - let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - - let mut where_clause = where_clause.cloned().unwrap_or(syn::parse_quote!(where)); - - if let Some(where_predicates) = &attrs.trait_bounds { - // if custom trait bounds are given, append those to the where clause. - where_clause.predicates.extend(where_predicates.clone()); - } else { - // else, append our default bounds to each parameter to ensure that it all lines up with our generated impls and such: - for param in generics.type_params() { - let ty = ¶m.ident; - where_clause.predicates.push(syn::parse_quote!(#ty: #path_to_crate::IntoVisitor)); - where_clause.predicates.push(syn::parse_quote!(#path_to_crate::Error: From<<<#ty as #path_to_crate::IntoVisitor>::Visitor as #path_to_crate::Visitor>::Error>)); + + let type_resolver_ident = + syn::Ident::new(GenericTypes::TYPE_RESOLVER_IDENT_STR, Span::call_site()); + + // Where clause to use on Visitor/IntoVisitor + let visitor_where_clause = { + let (_, _, where_clause) = generics.split_for_impl(); + let mut where_clause = where_clause.cloned().unwrap_or(syn::parse_quote!(where)); + if let Some(where_predicates) = &attrs.trait_bounds { + // if custom trait bounds are given, append those to the where clause. + where_clause.predicates.extend(where_predicates.clone()); + } else { + // else, append our default bounds to each parameter to ensure that it all lines up with our generated impls and such: + for param in generics.type_params() { + let ty = ¶m.ident; + where_clause.predicates.push(syn::parse_quote!(#ty: #path_to_crate::IntoVisitor)); + } } - } + where_clause + }; - // Construct a type to put into PhantomData<$ty>. This takes lifetimes into account too. - let phantomdata_type: syn::Type = { + // (A, B, C, ScaleDecodeTypeResolver) style PhantomData type to use in Visitor struct. + let visitor_phantomdata_type = { let tys = generics.params.iter().filter_map::(|p| match p { syn::GenericParam::Type(ty) => { let ty = &ty.ident; @@ -427,10 +447,71 @@ fn handle_generics<'a>( // We don't need to mention const's in the PhantomData type. syn::GenericParam::Const(_) => None, }); + + // Add a param for the type resolver generic. + let tys = tys.chain(core::iter::once(syn::parse_quote!(#type_resolver_ident))); + syn::parse_quote!( (#( #tys, )*) ) }; - (impl_generics, ty_generics, where_clause, phantomdata_type) + // generics for our Visitor/IntoVisitor; we just add the type resolver param to the list. + let visitor_generics = { + let mut type_generics = generics.clone(); + let type_resolver_generic_param: syn::GenericParam = + syn::parse_quote!(#type_resolver_ident: #path_to_crate::TypeResolver); + + type_generics.params.push(type_resolver_generic_param); + type_generics + }; + + // generics for the type itself + let type_generics = generics; + + GenericTypes { + type_generics, + type_resolver_ident, + visitor_generics, + visitor_phantomdata_type, + visitor_where_clause, + } +} + +struct GenericTypes { + type_resolver_ident: syn::Ident, + type_generics: syn::Generics, + visitor_generics: syn::Generics, + visitor_where_clause: syn::WhereClause, + visitor_phantomdata_type: syn::Type, +} + +impl GenericTypes { + const TYPE_RESOLVER_IDENT_STR: &'static str = "ScaleDecodeTypeResolver"; + + pub fn ty_generics(&self) -> syn::TypeGenerics<'_> { + let (_, ty_generics, _) = self.type_generics.split_for_impl(); + ty_generics + } + pub fn impl_generics(&self) -> syn::ImplGenerics<'_> { + let (impl_generics, _, _) = self.type_generics.split_for_impl(); + impl_generics + } + pub fn visitor_where_clause(&self) -> &syn::WhereClause { + &self.visitor_where_clause + } + pub fn visitor_ty_generics(&self) -> syn::TypeGenerics<'_> { + let (_, ty_generics, _) = self.visitor_generics.split_for_impl(); + ty_generics + } + pub fn visitor_impl_generics(&self) -> syn::ImplGenerics<'_> { + let (impl_generics, _, _) = self.visitor_generics.split_for_impl(); + impl_generics + } + pub fn visitor_phantomdata_type(&self) -> &syn::Type { + &self.visitor_phantomdata_type + } + pub fn type_resolver_ident(&self) -> &syn::Ident { + &self.type_resolver_ident + } } struct TopLevelAttrs { diff --git a/scale-decode/Cargo.toml b/scale-decode/Cargo.toml index b8482b7..e147e1b 100644 --- a/scale-decode/Cargo.toml +++ b/scale-decode/Cargo.toml @@ -28,11 +28,12 @@ derive = ["dep:scale-decode-derive"] [dependencies] scale-info = { version = "2.7.0", default-features = false, features = ["bit-vec"] } codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } -scale-bits = { version = "0.4.0", default-features = false, features = ["scale-info"] } +scale-bits = { version = "0.5.0", default-features = false, features = ["scale-info"] } scale-decode-derive = { workspace = true, optional = true } primitive-types = { version = "0.12.0", optional = true, default-features = false } smallvec = "1.10.0" derive_more = { version = "0.99.17", default-features = false, features = ["from", "display"] } +scale-type-resolver = "0.1" [dev-dependencies] scale-info = { version = "2.7.0", default-features = false, features = ["bit-vec", "derive"] } diff --git a/scale-decode/README.md b/scale-decode/README.md index 314322b..d6b4018 100644 --- a/scale-decode/README.md +++ b/scale-decode/README.md @@ -21,10 +21,12 @@ generated. Here's an example of implementing `Visitor` to decode bytes into a custom `Value` type: ```rust +use std::marker::PhantomData; +use scale_decode::TypeResolver; use scale_decode::visitor::{ self, types::{Array, BitSequence, Composite, Sequence, Str, Tuple, Variant}, - TypeId, + TypeIdFor, }; // A custom type we'd like to decode into: @@ -54,187 +56,197 @@ enum Value { } // Implement the `Visitor` trait to define how to go from SCALE -// values into this type: -struct ValueVisitor; -impl visitor::Visitor for ValueVisitor { - type Value<'scale, 'info> = Value; +// values into this type. Here, we are choosing to be generic over +// how types are resolved, which is a good default choice when creating +// a visitor unless you rely on a specific type resolver/ID type. +struct ValueVisitor(PhantomData); + +impl ValueVisitor { + fn new() -> Self { + Self(PhantomData) + } +} + +impl visitor::Visitor for ValueVisitor { + type Value<'scale, 'resolver> = Value; type Error = visitor::DecodeError; + type TypeResolver = R; - fn visit_bool<'scale, 'info>( + fn visit_bool<'scale, 'resolver>( self, value: bool, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::Bool(value)) } - fn visit_char<'scale, 'info>( + fn visit_char<'scale, 'resolver>( self, value: char, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::Char(value)) } - fn visit_u8<'scale, 'info>( + fn visit_u8<'scale, 'resolver>( self, value: u8, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::U8(value)) } - fn visit_u16<'scale, 'info>( + fn visit_u16<'scale, 'resolver>( self, value: u16, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::U16(value)) } - fn visit_u32<'scale, 'info>( + fn visit_u32<'scale, 'resolver>( self, value: u32, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::U32(value)) } - fn visit_u64<'scale, 'info>( + fn visit_u64<'scale, 'resolver>( self, value: u64, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::U64(value)) } - fn visit_u128<'scale, 'info>( + fn visit_u128<'scale, 'resolver>( self, value: u128, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::U128(value)) } - fn visit_u256<'info>( + fn visit_u256<'scale, 'resolver>( self, - value: &'_ [u8; 32], - _type_id: TypeId, - ) -> Result, Self::Error> { + value: &'scale [u8; 32], + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::U256(*value)) } - fn visit_i8<'scale, 'info>( + fn visit_i8<'scale, 'resolver>( self, value: i8, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::I8(value)) } - fn visit_i16<'scale, 'info>( + fn visit_i16<'scale, 'resolver>( self, value: i16, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::I16(value)) } - fn visit_i32<'scale, 'info>( + fn visit_i32<'scale, 'resolver>( self, value: i32, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::I32(value)) } - fn visit_i64<'scale, 'info>( + fn visit_i64<'scale, 'resolver>( self, value: i64, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::I64(value)) } - fn visit_i128<'scale, 'info>( + fn visit_i128<'scale, 'resolver>( self, value: i128, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::I128(value)) } - fn visit_i256<'info>( + fn visit_i256<'scale, 'resolver>( self, - value: &'_ [u8; 32], - _type_id: TypeId, - ) -> Result, Self::Error> { + value: &'scale [u8; 32], + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::I256(*value)) } - fn visit_sequence<'scale, 'info>( + fn visit_sequence<'scale, 'resolver>( self, - value: &mut Sequence<'scale, 'info>, - _type_id: TypeId, - ) -> Result, Self::Error> { + value: &mut Sequence<'scale, 'resolver, Self::TypeResolver>, + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { let mut vals = vec![]; - while let Some(val) = value.decode_item(ValueVisitor) { + while let Some(val) = value.decode_item(ValueVisitor::new()) { let val = val?; vals.push(val); } Ok(Value::Sequence(vals)) } - fn visit_composite<'scale, 'info>( + fn visit_composite<'scale, 'resolver>( self, - value: &mut Composite<'scale, 'info>, - _type_id: TypeId, - ) -> Result, Self::Error> { + value: &mut Composite<'scale, 'resolver, Self::TypeResolver>, + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { let mut vals = vec![]; for item in value.by_ref() { let item = item?; - let val = item.decode_with_visitor(ValueVisitor)?; + let val = item.decode_with_visitor(ValueVisitor::new())?; let name = item.name().unwrap_or("").to_owned(); vals.push((name, val)); } Ok(Value::Composite(vals)) } - fn visit_tuple<'scale, 'info>( + fn visit_tuple<'scale, 'resolver>( self, - value: &mut Tuple<'scale, 'info>, - _type_id: TypeId, - ) -> Result, Self::Error> { + value: &mut Tuple<'scale, 'resolver, Self::TypeResolver>, + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { let mut vals = vec![]; - while let Some(val) = value.decode_item(ValueVisitor) { + while let Some(val) = value.decode_item(ValueVisitor::new()) { let val = val?; vals.push(val); } Ok(Value::Tuple(vals)) } - fn visit_str<'scale, 'info>( + fn visit_str<'scale, 'resolver>( self, value: &mut Str<'scale>, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::Str(value.as_str()?.to_owned())) } - fn visit_variant<'scale, 'info>( + fn visit_variant<'scale, 'resolver>( self, - value: &mut Variant<'scale, 'info>, - _type_id: TypeId, - ) -> Result, Self::Error> { + value: &mut Variant<'scale, 'resolver, Self::TypeResolver>, + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { let mut vals = vec![]; let fields = value.fields(); for item in fields.by_ref() { let item = item?; - let val = item.decode_with_visitor(ValueVisitor)?; + let val = item.decode_with_visitor(ValueVisitor::new())?; let name = item.name().unwrap_or("").to_owned(); vals.push((name, val)); } Ok(Value::Variant(value.name().to_owned(), vals)) } - fn visit_array<'scale, 'info>( + fn visit_array<'scale, 'resolver>( self, - value: &mut Array<'scale, 'info>, - _type_id: TypeId, - ) -> Result, Self::Error> { + value: &mut Array<'scale, 'resolver, Self::TypeResolver>, + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { let mut vals = vec![]; - while let Some(val) = value.decode_item(ValueVisitor) { + while let Some(val) = value.decode_item(ValueVisitor::new()) { let val = val?; vals.push(val); } Ok(Value::Array(vals)) } - fn visit_bitsequence<'scale, 'info>( + fn visit_bitsequence<'scale, 'resolver>( self, value: &mut BitSequence<'scale>, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { let bools: Result = value.decode()?.collect(); Ok(Value::BitSequence(bools?)) } @@ -244,7 +256,7 @@ impl visitor::Visitor for ValueVisitor { This can then be passed to a decode function like so: ```rust -let value: Value = scale_decode::visitor::decode_with_visitor(scale_bytes, type_id, types, ValueVisitor)?; +let value: Value = scale_decode::visitor::decode_with_visitor(scale_bytes, &type_id, &types, ValueVisitor::new())?; ``` Where `scale_bytes` are the bytes you'd like to decode, `type_id` is the type stored in the `types` registry @@ -255,9 +267,9 @@ If we were to then write an `IntoVisitor` implementation like so: ```rust impl scale_decode::IntoVisitor for Value { - type Visitor = ValueVisitor; - fn into_visitor() -> Self::Visitor { - ValueVisitor + type AnyVisitor = ValueVisitor; + fn into_visitor() -> Self::AnyVisitor { + ValueVisitor::new() } } ``` diff --git a/scale-decode/examples/enum_decode_as_type.rs b/scale-decode/examples/enum_decode_as_type.rs index 0e6d8d6..d959f8a 100644 --- a/scale-decode/examples/enum_decode_as_type.rs +++ b/scale-decode/examples/enum_decode_as_type.rs @@ -14,8 +14,11 @@ // limitations under the License. use codec::Encode; -use scale_decode::{error::ErrorKind, DecodeAsType, Error, IntoVisitor, Visitor}; +use scale_decode::{ + error::ErrorKind, visitor::TypeIdFor, DecodeAsType, Error, IntoVisitor, TypeResolver, Visitor, +}; use std::collections::HashMap; +use std::marker::PhantomData; // We have some enum Foo that we'll encode to bytes. The aim of this example is // to manually write a decoder for it. @@ -29,13 +32,19 @@ enum Foo { } // Define a struct that will be our `Visitor` capable of decoding to a `Foo`. -struct FooVisitor; +struct FooVisitor(PhantomData); + +impl FooVisitor { + fn new() -> Self { + Self(PhantomData) + } +} // Describe how to turn `Foo` into this visitor struct. impl IntoVisitor for Foo { - type Visitor = FooVisitor; - fn into_visitor() -> Self::Visitor { - FooVisitor + type AnyVisitor = FooVisitor; + fn into_visitor() -> Self::AnyVisitor { + FooVisitor(PhantomData) } } @@ -43,18 +52,19 @@ impl IntoVisitor for Foo { // any error type that can be converted into a `scale_decode::Error`), we'll also get a `DecodeAsType` // implementation for free (and it will compose nicely with other types that implement `DecodeAsType`). // We can opt not to do this if we prefer. -impl Visitor for FooVisitor { - type Value<'scale, 'info> = Foo; +impl Visitor for FooVisitor { + type Value<'scale, 'resolver> = Foo; type Error = Error; + type TypeResolver = R; // We have opted here to be quite flexible in what we support; we'll happily ignore fields in the input that we // don't care about and support unnamed to named fields. You could choose to be more strict if you prefer. We also // add context to any errors coming from decoding sub-types via `.map_err(|e| e.at_x(..))` calls. - fn visit_variant<'scale, 'info>( + fn visit_variant<'scale, 'resolver>( self, - value: &mut scale_decode::visitor::types::Variant<'scale, 'info>, - _type_id: scale_decode::visitor::TypeId, - ) -> Result, Self::Error> { + value: &mut scale_decode::visitor::types::Variant<'scale, 'resolver, Self::TypeResolver>, + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { if value.name() == "Bar" { // Here we choose to support decoding named or unnamed fields into our Bar variant. let fields = value.fields(); @@ -115,26 +125,34 @@ fn main() { let (type_id, types) = make_type::(); // We can decode via `DecodeAsType`, which is automatically implemented: - let bar_via_decode_as_type = Foo::decode_as_type(&mut &*bar_bytes, type_id, &types).unwrap(); + let bar_via_decode_as_type = Foo::decode_as_type(&mut &*bar_bytes, &type_id, &types).unwrap(); let wibble_via_decode_as_type = - Foo::decode_as_type(&mut &*wibble_bytes, type_id, &types).unwrap(); + Foo::decode_as_type(&mut &*wibble_bytes, &type_id, &types).unwrap(); let empty_via_decode_as_type = - Foo::decode_as_type(&mut &*empty_bytes, type_id, &types).unwrap(); + Foo::decode_as_type(&mut &*empty_bytes, &type_id, &types).unwrap(); // Or we can also manually use our `Visitor` impl: - let bar_via_visitor = - scale_decode::visitor::decode_with_visitor(&mut &*bar_bytes, type_id, &types, FooVisitor) - .unwrap(); + let bar_via_visitor = scale_decode::visitor::decode_with_visitor( + &mut &*bar_bytes, + &type_id, + &types, + FooVisitor::new(), + ) + .unwrap(); let wibble_via_visitor = scale_decode::visitor::decode_with_visitor( &mut &*wibble_bytes, - type_id, + &type_id, + &types, + FooVisitor::new(), + ) + .unwrap(); + let empty_via_visitor = scale_decode::visitor::decode_with_visitor( + &mut &*empty_bytes, + &type_id, &types, - FooVisitor, + FooVisitor::new(), ) .unwrap(); - let empty_via_visitor = - scale_decode::visitor::decode_with_visitor(&mut &*empty_bytes, type_id, &types, FooVisitor) - .unwrap(); assert_eq!(bar, bar_via_decode_as_type); assert_eq!(bar, bar_via_visitor); diff --git a/scale-decode/examples/struct_decode_as_type.rs b/scale-decode/examples/struct_decode_as_type.rs index 2ffd0ed..fdadd8a 100644 --- a/scale-decode/examples/struct_decode_as_type.rs +++ b/scale-decode/examples/struct_decode_as_type.rs @@ -14,8 +14,11 @@ // limitations under the License. use codec::Encode; -use scale_decode::{error::ErrorKind, DecodeAsType, Error, IntoVisitor, Visitor}; +use scale_decode::{ + error::ErrorKind, visitor::TypeIdFor, DecodeAsType, Error, IntoVisitor, TypeResolver, Visitor, +}; use std::collections::HashMap; +use std::marker::PhantomData; // We have some struct Foo that we'll encode to bytes. The aim of this example is // to manually write a decoder for it. @@ -28,13 +31,19 @@ struct Foo { } // Define a struct that will be our `Visitor` capable of decoding to a `Foo`. -struct FooVisitor; +struct FooVisitor(PhantomData); + +impl FooVisitor { + fn new() -> Self { + Self(PhantomData) + } +} // Describe how to turn `Foo` into this visitor struct. impl IntoVisitor for Foo { - type Visitor = FooVisitor; - fn into_visitor() -> Self::Visitor { - FooVisitor + type AnyVisitor = FooVisitor; + fn into_visitor() -> Self::AnyVisitor { + FooVisitor(PhantomData) } } @@ -42,19 +51,20 @@ impl IntoVisitor for Foo { // any error type that can be converted into a `scale_decode::Error`), we'll also get a `DecodeAsType` // implementation for free (and it will compose nicely with other types that implement `DecodeAsType`). // We can opt not to do this if we prefer. -impl Visitor for FooVisitor { - type Value<'scale, 'info> = Foo; +impl Visitor for FooVisitor { + type Value<'scale, 'resolver> = Foo; type Error = Error; + type TypeResolver = R; // Support decoding from composite types. We support decoding from either named or // unnamed fields (matching by field index if unnamed) and add context to errors via // `.map_err(|e| e.at_x(..))` calls to give back more precise information about where // decoding failed, if it does. - fn visit_composite<'scale, 'info>( + fn visit_composite<'scale, 'resolver>( self, - value: &mut scale_decode::visitor::types::Composite<'scale, 'info>, - type_id: scale_decode::visitor::TypeId, - ) -> Result, Self::Error> { + value: &mut scale_decode::visitor::types::Composite<'scale, 'resolver, Self::TypeResolver>, + type_id: &TypeIdFor, + ) -> Result, Self::Error> { if value.has_unnamed_fields() { // handle it like a tuple if there are unnamed fields in it: return self.visit_tuple(&mut value.as_tuple(), type_id); @@ -77,11 +87,11 @@ impl Visitor for FooVisitor { } // If we like, we can also support decoding from tuples of matching lengths: - fn visit_tuple<'scale, 'info>( + fn visit_tuple<'scale, 'resolver>( self, - value: &mut scale_decode::visitor::types::Tuple<'scale, 'info>, - _type_id: scale_decode::visitor::TypeId, - ) -> Result, Self::Error> { + value: &mut scale_decode::visitor::types::Tuple<'scale, 'resolver, Self::TypeResolver>, + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { if value.remaining() != 2 { return Err(Error::new(ErrorKind::WrongLength { actual_len: value.remaining(), @@ -109,14 +119,18 @@ fn main() { let (type_id, types) = make_type::(); // We can decode via `DecodeAsType`, which is automatically implemented: - let foo_via_decode_as_type = Foo::decode_as_type(&mut &*foo_bytes, type_id, &types).unwrap(); + let foo_via_decode_as_type = Foo::decode_as_type(&mut &*foo_bytes, &type_id, &types).unwrap(); // We can also attempt to decode it into any other type; we'll get an error if this fails: let foo_via_decode_as_type_arc = - >::decode_as_type(&mut &*foo_bytes, type_id, &types).unwrap(); + >::decode_as_type(&mut &*foo_bytes, &type_id, &types).unwrap(); // Or we can also manually use our `Visitor` impl: - let foo_via_visitor = - scale_decode::visitor::decode_with_visitor(&mut &*foo_bytes, type_id, &types, FooVisitor) - .unwrap(); + let foo_via_visitor = scale_decode::visitor::decode_with_visitor( + &mut &*foo_bytes, + &type_id, + &types, + FooVisitor::new(), + ) + .unwrap(); assert_eq!(foo_original, foo_via_decode_as_type); assert_eq!(&foo_original, &*foo_via_decode_as_type_arc); diff --git a/scale-decode/examples/visitor.rs b/scale-decode/examples/visitor.rs index 9fc9fd4..e1e920b 100644 --- a/scale-decode/examples/visitor.rs +++ b/scale-decode/examples/visitor.rs @@ -12,13 +12,14 @@ // 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 codec::Encode; use scale_decode::visitor::{ self, types::{Array, BitSequence, Composite, Sequence, Str, Tuple, Variant}, - TypeId, + TypeIdFor, }; +use scale_decode::TypeResolver; +use std::marker::PhantomData; // A custom type we'd like to decode into: #[derive(Debug, PartialEq)] @@ -47,187 +48,197 @@ enum Value { } // Implement the `Visitor` trait to define how to go from SCALE -// values into this type: -struct ValueVisitor; -impl visitor::Visitor for ValueVisitor { - type Value<'scale, 'info> = Value; +// values into this type. Here, we are choosing to be generic over +// how types are resolved, which is a good default choice when creating +// a visitor unless you rely on a specific type resolver/ID type. +struct ValueVisitor(PhantomData); + +impl ValueVisitor { + fn new() -> Self { + Self(PhantomData) + } +} + +impl visitor::Visitor for ValueVisitor { + type Value<'scale, 'resolver> = Value; type Error = visitor::DecodeError; + type TypeResolver = R; - fn visit_bool<'scale, 'info>( + fn visit_bool<'scale, 'resolver>( self, value: bool, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::Bool(value)) } - fn visit_char<'scale, 'info>( + fn visit_char<'scale, 'resolver>( self, value: char, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::Char(value)) } - fn visit_u8<'scale, 'info>( + fn visit_u8<'scale, 'resolver>( self, value: u8, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::U8(value)) } - fn visit_u16<'scale, 'info>( + fn visit_u16<'scale, 'resolver>( self, value: u16, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::U16(value)) } - fn visit_u32<'scale, 'info>( + fn visit_u32<'scale, 'resolver>( self, value: u32, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::U32(value)) } - fn visit_u64<'scale, 'info>( + fn visit_u64<'scale, 'resolver>( self, value: u64, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::U64(value)) } - fn visit_u128<'scale, 'info>( + fn visit_u128<'scale, 'resolver>( self, value: u128, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::U128(value)) } - fn visit_u256<'info>( + fn visit_u256<'scale, 'resolver>( self, - value: &'_ [u8; 32], - _type_id: TypeId, - ) -> Result, Self::Error> { + value: &'scale [u8; 32], + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::U256(*value)) } - fn visit_i8<'scale, 'info>( + fn visit_i8<'scale, 'resolver>( self, value: i8, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::I8(value)) } - fn visit_i16<'scale, 'info>( + fn visit_i16<'scale, 'resolver>( self, value: i16, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::I16(value)) } - fn visit_i32<'scale, 'info>( + fn visit_i32<'scale, 'resolver>( self, value: i32, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::I32(value)) } - fn visit_i64<'scale, 'info>( + fn visit_i64<'scale, 'resolver>( self, value: i64, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::I64(value)) } - fn visit_i128<'scale, 'info>( + fn visit_i128<'scale, 'resolver>( self, value: i128, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::I128(value)) } - fn visit_i256<'info>( + fn visit_i256<'scale, 'resolver>( self, - value: &'_ [u8; 32], - _type_id: TypeId, - ) -> Result, Self::Error> { + value: &'scale [u8; 32], + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::I256(*value)) } - fn visit_sequence<'scale, 'info>( + fn visit_sequence<'scale, 'resolver>( self, - value: &mut Sequence<'scale, 'info>, - _type_id: TypeId, - ) -> Result, Self::Error> { + value: &mut Sequence<'scale, 'resolver, Self::TypeResolver>, + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { let mut vals = vec![]; - while let Some(val) = value.decode_item(ValueVisitor) { + while let Some(val) = value.decode_item(ValueVisitor::new()) { let val = val?; vals.push(val); } Ok(Value::Sequence(vals)) } - fn visit_composite<'scale, 'info>( + fn visit_composite<'scale, 'resolver>( self, - value: &mut Composite<'scale, 'info>, - _type_id: TypeId, - ) -> Result, Self::Error> { + value: &mut Composite<'scale, 'resolver, Self::TypeResolver>, + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { let mut vals = vec![]; for item in value.by_ref() { let item = item?; - let val = item.decode_with_visitor(ValueVisitor)?; + let val = item.decode_with_visitor(ValueVisitor::new())?; let name = item.name().unwrap_or("").to_owned(); vals.push((name, val)); } Ok(Value::Composite(vals)) } - fn visit_tuple<'scale, 'info>( + fn visit_tuple<'scale, 'resolver>( self, - value: &mut Tuple<'scale, 'info>, - _type_id: TypeId, - ) -> Result, Self::Error> { + value: &mut Tuple<'scale, 'resolver, Self::TypeResolver>, + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { let mut vals = vec![]; - while let Some(val) = value.decode_item(ValueVisitor) { + while let Some(val) = value.decode_item(ValueVisitor::new()) { let val = val?; vals.push(val); } Ok(Value::Tuple(vals)) } - fn visit_str<'scale, 'info>( + fn visit_str<'scale, 'resolver>( self, value: &mut Str<'scale>, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::Str(value.as_str()?.to_owned())) } - fn visit_variant<'scale, 'info>( + fn visit_variant<'scale, 'resolver>( self, - value: &mut Variant<'scale, 'info>, - _type_id: TypeId, - ) -> Result, Self::Error> { + value: &mut Variant<'scale, 'resolver, Self::TypeResolver>, + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { let mut vals = vec![]; let fields = value.fields(); for item in fields.by_ref() { let item = item?; - let val = item.decode_with_visitor(ValueVisitor)?; + let val = item.decode_with_visitor(ValueVisitor::new())?; let name = item.name().unwrap_or("").to_owned(); vals.push((name, val)); } Ok(Value::Variant(value.name().to_owned(), vals)) } - fn visit_array<'scale, 'info>( + fn visit_array<'scale, 'resolver>( self, - value: &mut Array<'scale, 'info>, - _type_id: TypeId, - ) -> Result, Self::Error> { + value: &mut Array<'scale, 'resolver, Self::TypeResolver>, + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { let mut vals = vec![]; - while let Some(val) = value.decode_item(ValueVisitor) { + while let Some(val) = value.decode_item(ValueVisitor::new()) { let val = val?; vals.push(val); } Ok(Value::Array(vals)) } - fn visit_bitsequence<'scale, 'info>( + fn visit_bitsequence<'scale, 'resolver>( self, value: &mut BitSequence<'scale>, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { let bools: Result = value.decode()?.collect(); Ok(Value::BitSequence(bools?)) } @@ -252,8 +263,13 @@ fn main() { // Use scale_decode + type information to decode these bytes into our Value type: assert_eq!( - scale_decode::visitor::decode_with_visitor(&mut &*bytes, type_id, &types, ValueVisitor) - .unwrap(), + scale_decode::visitor::decode_with_visitor( + &mut &*bytes, + &type_id, + &types, + ValueVisitor::new() + ) + .unwrap(), Value::Variant( "Bar".to_owned(), vec![ diff --git a/scale-decode/src/impls/mod.rs b/scale-decode/src/impls/mod.rs index de61b44..fd87547 100644 --- a/scale-decode/src/impls/mod.rs +++ b/scale-decode/src/impls/mod.rs @@ -19,8 +19,7 @@ mod primitive_types; use crate::{ error::{Error, ErrorKind}, visitor::{ - self, decode_with_visitor, types::*, DecodeAsTypeResult, DecodeItemIterator, TypeId, - Visitor, + self, decode_with_visitor, types::*, DecodeAsTypeResult, DecodeItemIterator, Visitor, }, DecodeAsFields, FieldIter, IntoVisitor, }; @@ -45,21 +44,20 @@ use core::{ time::Duration, }; use scale_bits::Bits; +use scale_type_resolver::TypeResolver; -pub struct BasicVisitor { - _marker: core::marker::PhantomData, +pub struct BasicVisitor { + _marker: core::marker::PhantomData<(T, R)>, } /// Generate an [`IntoVisitor`] impl for basic types `T` where `BasicVisitor` impls `Visitor`. macro_rules! impl_into_visitor { - ($ty:ident $(< $($lt:lifetime,)* $($param:ident),* >)? $(where $( $where:tt )* )?) => { - impl $(< $($lt,)* $($param),* >)? crate::IntoVisitor for $ty $(< $($lt,)* $($param),* >)? - where - BasicVisitor<$ty $(< $($lt,)* $($param),* >)?>: for<'scale, 'info> Visitor = Self>, - $( $($where)* )? + ($ty:ident $(< $($param:ident),* >)? $(where $( $where:tt )* )?) => { + impl $(< $($param),* >)? crate::IntoVisitor for $ty $(< $($param),* >)? + where $( $($where)* )? { - type Visitor = BasicVisitor<$ty $(< $($lt,)* $($param),* >)?>; - fn into_visitor() -> Self::Visitor { + type AnyVisitor = BasicVisitor<$ty $(< $($param),* >)?, R>; + fn into_visitor() -> Self::AnyVisitor { BasicVisitor { _marker: core::marker::PhantomData } } } @@ -68,22 +66,22 @@ macro_rules! impl_into_visitor { /// Ignore single-field tuples/composites and visit the single field inside instead. macro_rules! visit_single_field_composite_tuple_impls { - () => { - fn visit_composite<'scale, 'info>( + ($type_resolver:ident) => { + fn visit_composite<'scale, 'resolver>( self, - value: &mut $crate::visitor::types::Composite<'scale, 'info>, - _type_id: $crate::visitor::TypeId, - ) -> Result, Self::Error> { + value: &mut $crate::visitor::types::Composite<'scale, 'resolver, $type_resolver>, + _type_id: &::TypeId, + ) -> Result, Self::Error> { if value.remaining() != 1 { return self.visit_unexpected($crate::visitor::Unexpected::Composite); } value.decode_item(self).unwrap() } - fn visit_tuple<'scale, 'info>( + fn visit_tuple<'scale, 'resolver>( self, - value: &mut $crate::visitor::types::Tuple<'scale, 'info>, - _type_id: $crate::visitor::TypeId, - ) -> Result, Self::Error> { + value: &mut $crate::visitor::types::Tuple<'scale, 'resolver, $type_resolver>, + _type_id: &::TypeId, + ) -> Result, Self::Error> { if value.remaining() != 1 { return self.visit_unexpected($crate::visitor::Unexpected::Tuple); } @@ -92,90 +90,95 @@ macro_rules! visit_single_field_composite_tuple_impls { }; } -impl Visitor for BasicVisitor { +impl Visitor for BasicVisitor { type Error = Error; - type Value<'scale, 'info> = char; + type Value<'scale, 'resolver> = char; + type TypeResolver = R; - fn visit_char<'scale, 'info>( + fn visit_char<'scale, 'resolver>( self, value: char, - _type_id: visitor::TypeId, - ) -> Result, Self::Error> { + _type_id: &::TypeId, + ) -> Result, Self::Error> { Ok(value) } - visit_single_field_composite_tuple_impls!(); + visit_single_field_composite_tuple_impls!(R); } impl_into_visitor!(char); -impl Visitor for BasicVisitor { +impl Visitor for BasicVisitor { type Error = Error; - type Value<'scale, 'info> = bool; + type Value<'scale, 'resolver> = bool; + type TypeResolver = R; - fn visit_bool<'scale, 'info>( + fn visit_bool<'scale, 'resolver>( self, value: bool, - _type_id: visitor::TypeId, - ) -> Result, Self::Error> { + _type_id: &::TypeId, + ) -> Result, Self::Error> { Ok(value) } - visit_single_field_composite_tuple_impls!(); + visit_single_field_composite_tuple_impls!(R); } impl_into_visitor!(bool); -impl Visitor for BasicVisitor { +impl Visitor for BasicVisitor { type Error = Error; - type Value<'scale, 'info> = String; + type Value<'scale, 'resolver> = String; + type TypeResolver = R; - fn visit_str<'scale, 'info>( + fn visit_str<'scale, 'resolver>( self, value: &mut Str<'scale>, - _type_id: visitor::TypeId, - ) -> Result, Self::Error> { + _type_id: &::TypeId, + ) -> Result, Self::Error> { let s = value.as_str()?.to_owned(); Ok(s) } - visit_single_field_composite_tuple_impls!(); + visit_single_field_composite_tuple_impls!(R); } impl_into_visitor!(String); -impl Visitor for BasicVisitor { +impl Visitor for BasicVisitor { type Error = Error; - type Value<'scale, 'info> = Bits; + type Value<'scale, 'resolver> = Bits; + type TypeResolver = R; - fn visit_bitsequence<'scale, 'info>( + fn visit_bitsequence<'scale, 'resolver>( self, value: &mut BitSequence<'scale>, - _type_id: visitor::TypeId, - ) -> Result, Self::Error> { + _type_id: &::TypeId, + ) -> Result, Self::Error> { value .decode()? .collect::>() .map_err(|e| Error::new(ErrorKind::VisitorDecodeError(e.into()))) } - visit_single_field_composite_tuple_impls!(); + visit_single_field_composite_tuple_impls!(R); } impl_into_visitor!(Bits); -impl Visitor for BasicVisitor> { +impl Visitor for BasicVisitor, R> { type Error = Error; - type Value<'scale, 'info> = PhantomData; + type Value<'scale, 'resolver> = PhantomData; + type TypeResolver = R; - fn visit_tuple<'scale, 'info>( + fn visit_tuple<'scale, 'resolver>( self, - value: &mut Tuple<'scale, 'info>, - _type_id: visitor::TypeId, - ) -> Result, Self::Error> { + value: &mut Tuple<'scale, 'resolver, R>, + _type_id: &::TypeId, + ) -> Result, Self::Error> { if value.remaining() == 0 { Ok(PhantomData) } else { self.visit_unexpected(visitor::Unexpected::Tuple) } } - fn visit_composite<'scale, 'info>( + fn visit_composite<'scale, 'resolver>( self, - value: &mut Composite<'scale, 'info>, - _type_id: visitor::TypeId, - ) -> Result, Self::Error> { + value: &mut Composite<'scale, 'resolver, R>, + _type_id: &::TypeId, + ) -> Result, Self::Error> { if value.remaining() == 0 { Ok(PhantomData) } else { @@ -188,29 +191,31 @@ impl_into_visitor!(PhantomData); // Generate impls to encode things based on some other type. We do this by implementing // `IntoVisitor` and using the `AndThen` combinator to map from an existing one to the desired output. macro_rules! impl_into_visitor_like { - ($target:ident $(< $($lt:lifetime,)* $($param:ident),* >)? as $source:ty $( [where $($where:tt)*] )?: $mapper:expr) => { - impl $(< $($lt,)* $($param),* >)? Visitor for BasicVisitor<$target $(< $($lt,)* $($param),* >)?> + ($target:ident $(< $($param:ident),* >)? as $source:ty $( [where $($where:tt)*] )?: $mapper:expr) => { + impl <$( $($param, )* )? Resolver> Visitor for BasicVisitor<$target $(< $($param),* >)?, Resolver> where $source: IntoVisitor, + Resolver: TypeResolver, $( $($where)* )? { - type Value<'scale, 'info> = $target $(< $($lt,)* $($param),* >)?; - type Error = <<$source as IntoVisitor>::Visitor as Visitor>::Error; + type Value<'scale, 'resolver> = $target $(< $($param),* >)?; + type Error = <<$source as IntoVisitor>::AnyVisitor as Visitor>::Error; + type TypeResolver = Resolver; - fn unchecked_decode_as_type<'scale, 'info>( + fn unchecked_decode_as_type<'scale, 'resolver>( self, input: &mut &'scale [u8], - type_id: TypeId, - types: &'info scale_info::PortableRegistry, - ) -> DecodeAsTypeResult, Self::Error>> { + type_id: &::TypeId, + types: &'resolver Self::TypeResolver, + ) -> DecodeAsTypeResult, Self::Error>> { // Use the source visitor to decode into some type: - let inner_res = decode_with_visitor(input, type_id.0, types, <$source>::into_visitor()); + let inner_res = decode_with_visitor(input, type_id, types, <$source>::into_visitor()); // map this type into our desired output and return it: let res = inner_res.map($mapper); DecodeAsTypeResult::Decoded(res) } } - impl_into_visitor!($target $(< $($lt,)* $($param),* >)?); + impl_into_visitor!($target $(< $($param),* >)? where $source: IntoVisitor); } } @@ -224,23 +229,25 @@ impl_into_visitor_like!(RangeInclusive as (T, T): |res: (T,T)| res.0..=res.1) // A custom implementation for `Cow` because it's rather tricky; the visitor we want is whatever the // `ToOwned` value for the Cow is, and Cow's have specific constraints, too. -impl<'a, T> Visitor for BasicVisitor> +impl<'a, T, R> Visitor for BasicVisitor, R> where T: 'a + ToOwned + ?Sized, ::Owned: IntoVisitor, + R: TypeResolver, { - type Value<'scale, 'info> = Cow<'a, T>; - type Error = <<::Owned as IntoVisitor>::Visitor as Visitor>::Error; + type Value<'scale, 'resolver> = Cow<'a, T>; + type Error = <<::Owned as IntoVisitor>::AnyVisitor as Visitor>::Error; + type TypeResolver = R; - fn unchecked_decode_as_type<'scale, 'info>( + fn unchecked_decode_as_type<'scale, 'resolver>( self, input: &mut &'scale [u8], - type_id: TypeId, - types: &'info scale_info::PortableRegistry, - ) -> DecodeAsTypeResult, Self::Error>> { + type_id: &::TypeId, + types: &'resolver Self::TypeResolver, + ) -> DecodeAsTypeResult, Self::Error>> { // Use the ToOwned visitor to decode into some type: let inner_res = - decode_with_visitor(input, type_id.0, types, <::Owned>::into_visitor()); + decode_with_visitor(input, type_id, types, <::Owned>::into_visitor()); // map this type into our owned Cow to return: let res = inner_res.map(Cow::Owned); DecodeAsTypeResult::Decoded(res) @@ -251,40 +258,42 @@ where T: 'a + ToOwned + ?Sized, ::Owned: IntoVisitor, { - type Visitor = BasicVisitor>; - fn into_visitor() -> Self::Visitor { + type AnyVisitor = BasicVisitor, R>; + fn into_visitor() -> Self::AnyVisitor { BasicVisitor { _marker: core::marker::PhantomData } } } macro_rules! impl_decode_seq_via_collect { ($ty:ident<$generic:ident> $(where $($where:tt)*)?) => { - impl <$generic> Visitor for BasicVisitor<$ty<$generic>> + impl <$generic, Resolver> Visitor for BasicVisitor<$ty<$generic>, Resolver> where $generic: IntoVisitor, + Resolver: TypeResolver, $( $($where)* )? { - type Value<'scale, 'info> = $ty<$generic>; + type Value<'scale, 'resolver> = $ty<$generic>; type Error = Error; + type TypeResolver = Resolver; - fn visit_sequence<'scale, 'info>( + fn visit_sequence<'scale, 'resolver>( self, - value: &mut Sequence<'scale, 'info>, - _type_id: visitor::TypeId, - ) -> Result, Self::Error> { - decode_items_using::<_, $generic>(value).collect() + value: &mut Sequence<'scale, 'resolver, Resolver>, + _type_id: &::TypeId, + ) -> Result, Self::Error> { + decode_items_using::<_, _, $generic>(value).collect() } - fn visit_array<'scale, 'info>( + fn visit_array<'scale, 'resolver>( self, - value: &mut Array<'scale, 'info>, - _type_id: visitor::TypeId, - ) -> Result, Self::Error> { - decode_items_using::<_, $generic>(value).collect() + value: &mut Array<'scale, 'resolver, Resolver>, + _type_id: &::TypeId, + ) -> Result, Self::Error> { + decode_items_using::<_, _, $generic>(value).collect() } - visit_single_field_composite_tuple_impls!(); + visit_single_field_composite_tuple_impls!(Resolver); } - impl_into_visitor!($ty < $generic > $( where $($where)* )?); + impl_into_visitor!($ty < $generic > where $generic: IntoVisitor, $( $($where)* )?); } } impl_decode_seq_via_collect!(Vec); @@ -297,7 +306,7 @@ impl_decode_seq_via_collect!(BTreeSet where T: Ord); // Like vecs, we can decode from tuples, sequences or arrays if the types line up ok. macro_rules! array_method_impl { ($value:ident, [$t:ident; $n:ident]) => {{ - let val = decode_items_using::<_, $t>($value).collect::, _>>()?; + let val = decode_items_using::<_, _, $t>($value).collect::, _>>()?; let actual_len = val.len(); let arr = val .try_into() @@ -305,52 +314,54 @@ macro_rules! array_method_impl { Ok(arr) }}; } -impl Visitor for BasicVisitor<[T; N]> { - type Value<'scale, 'info> = [T; N]; +impl Visitor for BasicVisitor<[T; N], R> { + type Value<'scale, 'resolver> = [T; N]; type Error = Error; + type TypeResolver = R; - fn visit_sequence<'scale, 'info>( + fn visit_sequence<'scale, 'resolver>( self, - value: &mut Sequence<'scale, 'info>, - _type_id: visitor::TypeId, - ) -> Result, Self::Error> { + value: &mut Sequence<'scale, 'resolver, R>, + _type_id: &::TypeId, + ) -> Result, Self::Error> { array_method_impl!(value, [T; N]) } - fn visit_array<'scale, 'info>( + fn visit_array<'scale, 'resolver>( self, - value: &mut Array<'scale, 'info>, - _type_id: visitor::TypeId, - ) -> Result, Self::Error> { + value: &mut Array<'scale, 'resolver, R>, + _type_id: &::TypeId, + ) -> Result, Self::Error> { array_method_impl!(value, [T; N]) } - visit_single_field_composite_tuple_impls!(); + visit_single_field_composite_tuple_impls!(R); } impl IntoVisitor for [T; N] { - type Visitor = BasicVisitor<[T; N]>; - fn into_visitor() -> Self::Visitor { + type AnyVisitor = BasicVisitor<[T; N], R>; + fn into_visitor() -> Self::AnyVisitor { BasicVisitor { _marker: core::marker::PhantomData } } } -impl Visitor for BasicVisitor> { +impl Visitor for BasicVisitor, R> { type Error = Error; - type Value<'scale, 'info> = BTreeMap; + type Value<'scale, 'resolver> = BTreeMap; + type TypeResolver = R; - fn visit_composite<'scale, 'info>( + fn visit_composite<'scale, 'resolver>( self, - value: &mut Composite<'scale, 'info>, - _type_id: visitor::TypeId, - ) -> Result, Self::Error> { + value: &mut Composite<'scale, 'resolver, R>, + _type_id: &::TypeId, + ) -> Result, Self::Error> { let mut map = BTreeMap::new(); while value.remaining() > 0 { // Get the name. If no name, skip over the corresponding value. let Some(key) = value.peek_name() else { - value.decode_item(crate::visitor::IgnoreVisitor).transpose()?; + value.decode_item(crate::visitor::IgnoreVisitor::::new()).transpose()?; continue; }; // Decode the value now that we have a valid name. - let Some(val) = value.decode_item(T::into_visitor()) else { break }; + let Some(val) = value.decode_item(T::into_visitor::()) else { break }; // Save to the map. let val = val.map_err(|e| e.at_field(key.to_owned()))?; map.insert(key.to_owned(), val); @@ -358,21 +369,27 @@ impl Visitor for BasicVisitor> { Ok(map) } } -impl_into_visitor!(BTreeMap); +impl IntoVisitor for BTreeMap { + type AnyVisitor = BasicVisitor, R>; + fn into_visitor() -> Self::AnyVisitor { + BasicVisitor { _marker: core::marker::PhantomData } + } +} -impl Visitor for BasicVisitor> { +impl Visitor for BasicVisitor, R> { type Error = Error; - type Value<'scale, 'info> = Option; + type Value<'scale, 'resolver> = Option; + type TypeResolver = R; - fn visit_variant<'scale, 'info>( + fn visit_variant<'scale, 'resolver>( self, - value: &mut Variant<'scale, 'info>, - _type_id: visitor::TypeId, - ) -> Result, Self::Error> { + value: &mut Variant<'scale, 'resolver, R>, + _type_id: &::TypeId, + ) -> Result, Self::Error> { if value.name() == "Some" && value.fields().remaining() == 1 { let val = value .fields() - .decode_item(T::into_visitor()) + .decode_item(T::into_visitor::()) .transpose() .map_err(|e| e.at_variant("Some"))? .expect("checked for 1 field already so should be ok"); @@ -386,23 +403,24 @@ impl Visitor for BasicVisitor> { })) } } - visit_single_field_composite_tuple_impls!(); + visit_single_field_composite_tuple_impls!(R); } -impl_into_visitor!(Option); +impl_into_visitor!(Option where T: IntoVisitor); -impl Visitor for BasicVisitor> { +impl Visitor for BasicVisitor, R> { type Error = Error; - type Value<'scale, 'info> = Result; + type Value<'scale, 'resolver> = Result; + type TypeResolver = R; - fn visit_variant<'scale, 'info>( + fn visit_variant<'scale, 'resolver>( self, - value: &mut Variant<'scale, 'info>, - _type_id: visitor::TypeId, - ) -> Result, Self::Error> { + value: &mut Variant<'scale, 'resolver, R>, + _type_id: &::TypeId, + ) -> Result, Self::Error> { if value.name() == "Ok" && value.fields().remaining() == 1 { let val = value .fields() - .decode_item(T::into_visitor()) + .decode_item(T::into_visitor::()) .transpose() .map_err(|e| e.at_variant("Ok"))? .expect("checked for 1 field already so should be ok"); @@ -410,7 +428,7 @@ impl Visitor for BasicVisitor> { } else if value.name() == "Err" && value.fields().remaining() == 1 { let val = value .fields() - .decode_item(E::into_visitor()) + .decode_item(E::into_visitor::()) .transpose() .map_err(|e| e.at_variant("Err"))? .expect("checked for 1 field already so should be ok"); @@ -422,18 +440,18 @@ impl Visitor for BasicVisitor> { })) } } - visit_single_field_composite_tuple_impls!(); + visit_single_field_composite_tuple_impls!(R); } -impl_into_visitor!(Result); +impl_into_visitor!(Result where T: IntoVisitor, E: IntoVisitor); // Impl Visitor/DecodeAsType for all primitive number types macro_rules! visit_number_fn_impl { ($name:ident : $ty:ty where |$res:ident| $expr:expr) => { - fn $name<'scale, 'info>( + fn $name<'scale, 'resolver>( self, value: $ty, - _type_id: visitor::TypeId, - ) -> Result, Self::Error> { + _type_id: &::TypeId, + ) -> Result, Self::Error> { let $res = value; let n = $expr.ok_or_else(|| { Error::new(ErrorKind::NumberOutOfRange { value: value.to_string() }) @@ -444,10 +462,11 @@ macro_rules! visit_number_fn_impl { } macro_rules! visit_number_impl { ($ty:ident where |$res:ident| $expr:expr) => { - #[allow(clippy::useless_conversion)] - impl Visitor for BasicVisitor<$ty> { + #[allow(clippy::unnecessary_fallible_conversions, clippy::useless_conversion)] + impl Visitor for BasicVisitor<$ty, R> { type Error = Error; - type Value<'scale, 'info> = $ty; + type Value<'scale, 'resolver> = $ty; + type TypeResolver = R; visit_number_fn_impl!(visit_u8: u8 where |$res| $expr); visit_number_fn_impl!(visit_u16: u16 where |$res| $expr); @@ -460,7 +479,7 @@ macro_rules! visit_number_impl { visit_number_fn_impl!(visit_i64: i64 where |$res| $expr); visit_number_fn_impl!(visit_i128: i128 where |$res| $expr); - visit_single_field_composite_tuple_impls!(); + visit_single_field_composite_tuple_impls!(R); } impl_into_visitor!($ty); }; @@ -516,7 +535,7 @@ macro_rules! tuple_method_impl { #[allow(unused_assignments)] { let v = $value - .decode_item($t::into_visitor()) + .decode_item($t::into_visitor::()) .transpose() .map_err(|e| e.at_idx(idx))? .expect("length already checked via .remaining()"); @@ -527,36 +546,42 @@ macro_rules! tuple_method_impl { )) }} } + macro_rules! decode_inner_type_when_one_tuple_entry { ($t:ident) => { - fn unchecked_decode_as_type<'scale, 'info>( + fn unchecked_decode_as_type<'scale, 'resolver>( self, input: &mut &'scale [u8], - type_id: TypeId, - types: &'info scale_info::PortableRegistry, - ) -> DecodeAsTypeResult, Self::Error>> { - // [jsdw]: See https://github.com/rust-lang/rustfmt/issues/5062. - // let else formatting not stable in macros; will keep indenting! - #[rustfmt::skip] - let Some(ty) = types.resolve(type_id.0) else { - return DecodeAsTypeResult::Skipped(self); - }; - - // Get the inner type ID if the thing we're trying to decode isn't - // a tuple or composite value. Else, fall back to default behaviour. - // This ensures that this function strictly improves on the default - // which would be to fail. - let inner_type_id = match &ty.type_def { - scale_info::TypeDef::Composite(_) => { - return DecodeAsTypeResult::Skipped(self); - } - scale_info::TypeDef::Tuple(_) => { - return DecodeAsTypeResult::Skipped(self); + type_id: &::TypeId, + types: &'resolver Self::TypeResolver, + ) -> DecodeAsTypeResult, Self::Error>> { + use scale_type_resolver::{ResolvedTypeVisitor, UnhandledKind}; + + // Match on the resolved kind; try to decode as inner type if it's not a + // composite, tuple, or a type ID we can't find. Else fall back to default. + struct TryDecodeAsInner(PhantomData); + impl<'resolver, TypeId: scale_type_resolver::TypeId + 'resolver> + ResolvedTypeVisitor<'resolver> for TryDecodeAsInner + { + type TypeId = TypeId; + type Value = bool; + fn visit_unhandled(self, kind: UnhandledKind) -> Self::Value { + match kind { + UnhandledKind::Composite + | UnhandledKind::Tuple + | UnhandledKind::NotFound => false, + _ => true, + } } - _ => type_id.0, - }; + } - let inner_res = decode_with_visitor(input, inner_type_id, types, <$t>::into_visitor()); + // If error decoding, or false, just fall back to default behaviour and don't try to decode as inner. + if let Err(_) | Ok(false) = types.resolve_type(type_id, TryDecodeAsInner(PhantomData)) { + return DecodeAsTypeResult::Skipped(self); + } + + // Else, try to decode as the inner type. + let inner_res = decode_with_visitor(input, type_id, types, <$t>::into_visitor()); let res = inner_res.map(|val| (val,)).map_err(|e| e.into()); DecodeAsTypeResult::Decoded(res) } @@ -567,30 +592,31 @@ macro_rules! decode_inner_type_when_one_tuple_entry { } macro_rules! impl_decode_tuple { ($($t:ident)*) => { - impl < $($t),* > Visitor for BasicVisitor<($($t,)*)> - where $( - $t: IntoVisitor, - )* + impl Visitor for BasicVisitor<($($t,)*), Resolver> + where + Resolver: TypeResolver, + $($t: IntoVisitor,)* { - type Value<'scale, 'info> = ($($t,)*); + type Value<'scale, 'resolver> = ($($t,)*); type Error = Error; + type TypeResolver = Resolver; // If we're trying to decode to a 1-tuple, and the type we're decoding - // isn't a tuple or composite, then decode thye inner type and add the tuple. + // isn't a tuple or composite, then decode the inner type and add the tuple. decode_inner_type_when_one_tuple_entry!($($t)*); - fn visit_composite<'scale, 'info>( + fn visit_composite<'scale, 'resolver>( self, - value: &mut Composite<'scale, 'info>, - _type_id: visitor::TypeId, - ) -> Result, Self::Error> { + value: &mut Composite<'scale, 'resolver, Resolver>, + _type_id: &::TypeId, + ) -> Result, Self::Error> { tuple_method_impl!(($($t,)*), value) } - fn visit_tuple<'scale, 'info>( + fn visit_tuple<'scale, 'resolver>( self, - value: &mut Tuple<'scale, 'info>, - _type_id: visitor::TypeId, - ) -> Result, Self::Error> { + value: &mut Tuple<'scale, 'resolver, Resolver>, + _type_id: &::TypeId, + ) -> Result, Self::Error> { tuple_method_impl!(($($t,)*), value) } } @@ -599,8 +625,8 @@ macro_rules! impl_decode_tuple { impl < $($t),* > IntoVisitor for ($($t,)*) where $( $t: IntoVisitor, )* { - type Visitor = BasicVisitor<($($t,)*)>; - fn into_visitor() -> Self::Visitor { + type AnyVisitor = BasicVisitor<($($t,)*), Resolver>; + fn into_visitor() -> Self::AnyVisitor { BasicVisitor { _marker: core::marker::PhantomData } } } @@ -609,9 +635,12 @@ macro_rules! impl_decode_tuple { impl < $($t),* > DecodeAsFields for ($($t,)*) where $( $t: IntoVisitor, )* { - fn decode_as_fields<'info>(input: &mut &[u8], fields: &mut dyn FieldIter<'info>, types: &'info scale_info::PortableRegistry) -> Result { - let mut composite = crate::visitor::types::Composite::new(input, crate::EMPTY_SCALE_INFO_PATH, fields, types, false); - let val = <($($t,)*)>::into_visitor().visit_composite(&mut composite, crate::visitor::TypeId(0)); + fn decode_as_fields<'resolver, Resolver: TypeResolver>(input: &mut &[u8], fields: &mut dyn FieldIter<'resolver, Resolver::TypeId>, types: &'resolver Resolver) -> Result { + let mut composite = crate::visitor::types::Composite::new(input, fields, types, false); + + // [jsdw] TODO: Passing a "default type ID" to a visitor just to satisfy the signature is + // a bit hideous (and requires `TypeId: Default`). Can we re-work this to avoid? + let val = <($($t,)*)>::into_visitor().visit_composite(&mut composite, &Default::default()); // Skip over bytes that we decoded: composite.skip_decoding()?; @@ -647,12 +676,13 @@ impl_decode_tuple!(A B C D E F G H I J K L M N O P Q R S T); // ^ Note: We make sure to support as many as parity-scale-codec's impls do. /// This takes anything that can decode a stream if items and return an iterator over them. -fn decode_items_using<'a, 'scale, 'info, D: DecodeItemIterator<'scale, 'info>, T>( +fn decode_items_using<'a, 'scale, 'resolver, R, D, T>( decoder: &'a mut D, ) -> impl Iterator> + 'a where T: IntoVisitor, - D: DecodeItemIterator<'scale, 'info>, + R: TypeResolver, + D: DecodeItemIterator<'scale, 'resolver, R>, { let mut idx = 0; core::iter::from_fn(move || { @@ -689,7 +719,7 @@ mod test { let (type_id, types) = make_type::(); let encoded = a.encode(); let decoded = - B::decode_as_type(&mut &*encoded, type_id, &types).expect("should be able to decode"); + B::decode_as_type(&mut &*encoded, &type_id, &types).expect("should be able to decode"); assert_eq!(&decoded, b); } @@ -737,11 +767,11 @@ mod test { let new_foo = match &types.resolve(ty).unwrap().type_def { scale_info::TypeDef::Composite(c) => { let mut field_iter = - c.fields.iter().map(|f| Field::new(f.ty.id, f.name.as_deref())); + c.fields.iter().map(|f| Field::new(&f.ty.id, f.name.as_deref())); Foo::decode_as_fields(foo_encoded_cursor, &mut field_iter, &types).unwrap() } scale_info::TypeDef::Tuple(t) => { - let mut field_iter = t.fields.iter().map(|f| Field::unnamed(f.id)); + let mut field_iter = t.fields.iter().map(|f| Field::unnamed(&f.id)); Foo::decode_as_fields(foo_encoded_cursor, &mut field_iter, &types).unwrap() } _ => { diff --git a/scale-decode/src/impls/primitive_types.rs b/scale-decode/src/impls/primitive_types.rs index 5bd8b6e..88eff7a 100644 --- a/scale-decode/src/impls/primitive_types.rs +++ b/scale-decode/src/impls/primitive_types.rs @@ -20,27 +20,29 @@ use crate::{ IntoVisitor, }; use primitive_types::{H128, H160, H256, H384, H512, H768}; +use scale_type_resolver::TypeResolver; macro_rules! impl_visitor { ($ty:ty: $len:literal) => { - impl Visitor for BasicVisitor<$ty> { + impl Visitor for BasicVisitor<$ty, R> { type Error = Error; - type Value<'scale, 'info> = $ty; + type Value<'scale, 'resolver> = $ty; + type TypeResolver = R; - fn unchecked_decode_as_type<'scale, 'info>( + fn unchecked_decode_as_type<'scale, 'resolver>( self, input: &mut &'scale [u8], - type_id: crate::visitor::TypeId, - types: &'info scale_info::PortableRegistry, + type_id: &::TypeId, + types: &'resolver Self::TypeResolver, ) -> crate::visitor::DecodeAsTypeResult< Self, - Result, Self::Error>, + Result, Self::Error>, > { let res = decode_with_visitor( input, - type_id.0, + type_id, types, - BasicVisitor::<[u8; $len / 8]> { _marker: core::marker::PhantomData }, + BasicVisitor::<[u8; $len / 8], R> { _marker: core::marker::PhantomData }, ) .map(|res| <$ty>::from(res)); DecodeAsTypeResult::Decoded(res) @@ -48,8 +50,8 @@ macro_rules! impl_visitor { } impl IntoVisitor for $ty { - type Visitor = BasicVisitor<$ty>; - fn into_visitor() -> Self::Visitor { + type AnyVisitor = BasicVisitor<$ty, R>; + fn into_visitor() -> Self::AnyVisitor { BasicVisitor { _marker: core::marker::PhantomData } } } diff --git a/scale-decode/src/lib.rs b/scale-decode/src/lib.rs index a7c0308..4a4d438 100644 --- a/scale-decode/src/lib.rs +++ b/scale-decode/src/lib.rs @@ -55,7 +55,7 @@ fn get_type_info() -> (u32, PortableRegistry) { let mut types = scale_info::Registry::new(); let ty = types.register_type(&m); let portable_registry: PortableRegistry = types.into(); - (ty.id(), portable_registry) + (ty.id, portable_registry) } // Encode the left value statically. @@ -68,7 +68,7 @@ where { let (type_id, types) = get_type_info::(); let a_bytes = a.encode(); - let new_b = B::decode_as_type(&mut &*a_bytes, type_id, &types).unwrap(); + let new_b = B::decode_as_type(&mut &*a_bytes, &type_id, &types).unwrap(); assert_eq!(b, new_b); } @@ -145,12 +145,11 @@ pub mod error; pub mod visitor; pub use crate::error::Error; +pub use scale_type_resolver::Field; +pub use scale_type_resolver::FieldIter; +pub use scale_type_resolver::TypeResolver; pub use visitor::Visitor; -// Used in trait definitions. -use scale_info::form::PortableForm; -pub use scale_info::PortableRegistry; - // This is exported for generated derive code to use, to be compatible with std or no-std as needed. #[doc(hidden)] pub use alloc::{collections::BTreeMap, string::ToString, vec}; @@ -159,10 +158,9 @@ pub use alloc::{collections::BTreeMap, string::ToString, vec}; pub mod ext { #[cfg(feature = "primitive-types")] pub use primitive_types; + pub use scale_type_resolver; } -use alloc::vec::Vec; - /// This trait is implemented for any type `T` where `T` implements [`IntoVisitor`] and the errors returned /// from this [`Visitor`] can be converted into [`Error`]. It's essentially a convenience wrapper around /// [`visitor::decode_with_visitor`] that mirrors `scale-encode`'s `EncodeAsType`. @@ -170,10 +168,10 @@ pub trait DecodeAsType: Sized + IntoVisitor { /// Given some input bytes, a `type_id`, and type registry, attempt to decode said bytes into /// `Self`. Implementations should modify the `&mut` reference to the bytes such that any bytes /// not used in the course of decoding are still pointed to after decoding is complete. - fn decode_as_type( + fn decode_as_type( input: &mut &[u8], - type_id: u32, - types: &PortableRegistry, + type_id: &R::TypeId, + types: &R, ) -> Result { Self::decode_as_type_maybe_compact(input, type_id, types, false) } @@ -184,26 +182,26 @@ pub trait DecodeAsType: Sized + IntoVisitor { /// /// If is_compact=true, it is assumed the value is compact encoded (only works for some types). #[doc(hidden)] - fn decode_as_type_maybe_compact( + fn decode_as_type_maybe_compact( input: &mut &[u8], - type_id: u32, - types: &PortableRegistry, + type_id: &R::TypeId, + types: &R, is_compact: bool, ) -> Result; } impl DecodeAsType for T { - fn decode_as_type_maybe_compact( + fn decode_as_type_maybe_compact( input: &mut &[u8], - type_id: u32, - types: &scale_info::PortableRegistry, + type_id: &R::TypeId, + types: &R, is_compact: bool, ) -> Result { let res = visitor::decode_with_visitor_maybe_compact( input, type_id, types, - T::into_visitor(), + T::into_visitor::(), is_compact, )?; Ok(res) @@ -215,53 +213,13 @@ impl DecodeAsType for T { /// for tuple and struct types, and is automatically implemented via the [`macro@DecodeAsType`] macro. pub trait DecodeAsFields: Sized { /// Given some bytes and some fields denoting their structure, attempt to decode. - fn decode_as_fields<'info>( + fn decode_as_fields<'resolver, R: TypeResolver>( input: &mut &[u8], - fields: &mut dyn FieldIter<'info>, - types: &'info PortableRegistry, + fields: &mut dyn FieldIter<'resolver, R::TypeId>, + types: &'resolver R, ) -> Result; } -/// A representation of a single field to be encoded via [`DecodeAsFields::decode_as_fields`]. -#[derive(Debug, Clone, Copy)] -pub struct Field<'a> { - name: Option<&'a str>, - id: u32, -} - -impl<'a> Field<'a> { - /// Construct a new field with an ID and optional name. - pub fn new(id: u32, name: Option<&'a str>) -> Self { - Field { id, name } - } - /// Create a new unnamed field. - pub fn unnamed(id: u32) -> Self { - Field { name: None, id } - } - /// Create a new named field. - pub fn named(id: u32, name: &'a str) -> Self { - Field { name: Some(name), id } - } - /// The field name, if any. - pub fn name(&self) -> Option<&'a str> { - self.name - } - /// The field ID. - pub fn id(&self) -> u32 { - self.id - } -} - -impl<'a> From<&'a scale_info::Field> for Field<'a> { - fn from(value: &'a scale_info::Field) -> Self { - Field { name: value.name.as_deref(), id: value.ty.id } - } -} - -/// An iterator over a set of fields. -pub trait FieldIter<'a>: Iterator> {} -impl<'a, T> FieldIter<'a> for T where T: Iterator> {} - /// This trait can be implemented on any type that has an associated [`Visitor`] responsible for decoding /// SCALE encoded bytes to it whose error type is [`Error`]. Anything that implements this trait gets a /// [`DecodeAsType`] implementation for free. @@ -272,17 +230,15 @@ impl<'a, T> FieldIter<'a> for T where T: Iterator> {} // rather than rely on auto conversion, if they care about also being able to impl `DecodeAsType`. pub trait IntoVisitor { /// The visitor type used to decode SCALE encoded bytes to `Self`. - type Visitor: for<'scale, 'info> visitor::Visitor = Self, Error = Error>; + type AnyVisitor: for<'scale, 'resolver> visitor::Visitor< + Value<'scale, 'resolver> = Self, + Error = Error, + TypeResolver = R, + >; /// A means of obtaining this visitor. - fn into_visitor() -> Self::Visitor; + fn into_visitor() -> Self::AnyVisitor; } -// In a few places, we need an empty path with a lifetime that outlives 'info, -// so here's one that lives forever that we can use. -#[doc(hidden)] -pub static EMPTY_SCALE_INFO_PATH: &scale_info::Path = - &scale_info::Path { segments: Vec::new() }; - /// The `DecodeAsType` derive macro can be used to implement `DecodeAsType` on structs and enums whose /// fields all implement `DecodeAsType`. Under the hood, the macro generates `scale_decode::visitor::Visitor` /// and `scale_decode::IntoVisitor` implementations for each type (as well as an associated `Visitor` struct), diff --git a/scale-decode/src/visitor/decode.rs b/scale-decode/src/visitor/decode.rs index 4b18d9a..766892c 100644 --- a/scale-decode/src/visitor/decode.rs +++ b/scale-decode/src/visitor/decode.rs @@ -12,329 +12,343 @@ // 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 crate::visitor::{ - Array, BitSequence, Composite, DecodeAsTypeResult, DecodeError, Sequence, Str, Tuple, TypeId, - Variant, Visitor, + Array, BitSequence, Composite, DecodeAsTypeResult, DecodeError, Sequence, Str, Tuple, + TypeIdFor, Variant, Visitor, }; use crate::Field; +use alloc::format; +use alloc::string::ToString; use codec::{self, Decode}; -use scale_info::Type; -use scale_info::{ - form::PortableForm, Path, PortableRegistry, TypeDef, TypeDefArray, TypeDefBitSequence, - TypeDefComposite, TypeDefPrimitive, TypeDefSequence, TypeDefTuple, TypeDefVariant, +use scale_type_resolver::{ + BitsOrderFormat, BitsStoreFormat, FieldIter, Primitive, ResolvedTypeVisitor, TypeResolver, + UnhandledKind, VariantIter, }; -/// Decode data according to the type ID and [`PortableRegistry`] provided. +/// Decode data according to the type ID and type resolver provided. /// 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_with_visitor<'scale, 'info, V: Visitor>( +pub fn decode_with_visitor<'scale, 'resolver, V: Visitor>( data: &mut &'scale [u8], - ty_id: u32, - types: &'info PortableRegistry, + ty_id: &TypeIdFor, + types: &'resolver V::TypeResolver, visitor: V, -) -> Result, V::Error> { +) -> Result, V::Error> { decode_with_visitor_maybe_compact(data, ty_id, types, visitor, false) } -macro_rules! err_if_compact { - ($is_compact:expr, $ty:expr) => { - if $is_compact { - return Err(DecodeError::CannotDecodeCompactIntoType($ty.clone().into()).into()); - } - }; -} - -pub fn decode_with_visitor_maybe_compact<'scale, 'info, V: Visitor>( +pub fn decode_with_visitor_maybe_compact<'scale, 'resolver, V: Visitor>( data: &mut &'scale [u8], - ty_id: u32, - types: &'info PortableRegistry, + ty_id: &TypeIdFor, + types: &'resolver V::TypeResolver, visitor: V, is_compact: bool, -) -> Result, V::Error> { +) -> Result, V::Error> { // Provide option to "bail out" and do something custom first. - let visitor = match visitor.unchecked_decode_as_type(data, TypeId(ty_id), types) { + let visitor = match visitor.unchecked_decode_as_type(data, ty_id, types) { DecodeAsTypeResult::Decoded(r) => return r, DecodeAsTypeResult::Skipped(v) => v, }; - let ty = types.resolve(ty_id).ok_or(DecodeError::TypeIdNotFound(ty_id))?; - let ty_id = TypeId(ty_id); - let path = &ty.path; + let decoder = Decoder::new(data, types, ty_id, visitor, is_compact); + let res = types.resolve_type(ty_id, decoder); - match &ty.type_def { - TypeDef::Composite(inner) => { - decode_composite_value(data, ty_id, path, inner, ty, types, visitor, is_compact) - } - TypeDef::Variant(inner) => { - err_if_compact!(is_compact, ty); - decode_variant_value(data, ty_id, path, inner, types, visitor) - } - TypeDef::Sequence(inner) => { - err_if_compact!(is_compact, ty); - decode_sequence_value(data, ty_id, inner, types, visitor) - } - TypeDef::Array(inner) => { - err_if_compact!(is_compact, ty); - decode_array_value(data, ty_id, inner, types, visitor) - } - TypeDef::Tuple(inner) => decode_tuple_value(data, ty_id, inner, types, visitor, is_compact), - TypeDef::Primitive(inner) => { - decode_primitive_value(data, ty_id, inner, visitor, is_compact) - } - TypeDef::Compact(inner) => { - decode_with_visitor_maybe_compact(data, inner.type_param.id, types, visitor, true) - } - TypeDef::BitSequence(inner) => { - err_if_compact!(is_compact, ty); - decode_bit_sequence_value(data, ty_id, inner, types, visitor) + match res { + // We got a value back; return it + Ok(Ok(val)) => Ok(val), + // We got a visitor error back; return it + Ok(Err(e)) => Err(e), + // We got a TypeResolver error back; turn it into a DecodeError and then visitor error to return. + Err(resolve_type_error) => { + Err(DecodeError::TypeResolvingError(resolve_type_error.to_string()).into()) } } } -/// Note: Only `U8`, `U16`, `U32`, `U64`, `U128` allow compact encoding and should be provided for the `compact_type` argument. -#[allow(clippy::too_many_arguments)] -fn decode_composite_value<'scale, 'info, V: Visitor>( - data: &mut &'scale [u8], - ty_id: TypeId, - path: &'info Path, - ty: &'info TypeDefComposite, - ty_super: &'info Type, - types: &'info PortableRegistry, +/// This struct implements `ResolvedTypeVisitor`. One of those methods fired depending on the type that +/// we resolve from the given TypeId, and then based on the information handed to that method we decode +/// the SCALE encoded bytes as needed and then call the relevant method on the `scale_decode::Visitor` to +/// hand back the decoded value (or some nice interface to allow the user to decode the value). +struct Decoder<'a, 'scale, 'resolver, V: Visitor> { + data: &'a mut &'scale [u8], + type_id: &'a TypeIdFor, + types: &'resolver V::TypeResolver, visitor: V, is_compact: bool, -) -> Result, V::Error> { - // guard against invalid compact types: only composites with 1 field can be compact encoded - if is_compact && ty.fields.len() != 1 { - return Err(DecodeError::CannotDecodeCompactIntoType(ty_super.clone()).into()); +} + +impl<'a, 'scale, 'resolver, V: Visitor> Decoder<'a, 'scale, 'resolver, V> { + fn new( + data: &'a mut &'scale [u8], + types: &'resolver V::TypeResolver, + type_id: &'a TypeIdFor, + visitor: V, + is_compact: bool, + ) -> Self { + Decoder { data, type_id, types, is_compact, visitor } } +} - let mut fields = ty.fields.iter().map(|f| Field::new(f.ty.id, f.name.as_deref())); - let mut items = Composite::new(data, path, &mut fields, types, is_compact); - let res = visitor.visit_composite(&mut items, ty_id); +impl<'a, 'scale, 'resolver, V: Visitor> ResolvedTypeVisitor<'resolver> + for Decoder<'a, 'scale, 'resolver, V> +{ + type TypeId = TypeIdFor; + type Value = Result, V::Error>; - // Skip over any bytes that the visitor chose not to decode: - items.skip_decoding()?; - *data = items.bytes_from_undecoded(); + fn visit_unhandled(self, kind: UnhandledKind) -> Self::Value { + let type_id = self.type_id; + Err(DecodeError::TypeIdNotFound(format!( + "Kind {kind:?} (type ID {type_id:?}) has not been properly handled" + )) + .into()) + } - res -} + fn visit_not_found(self) -> Self::Value { + let type_id = self.type_id; + Err(DecodeError::TypeIdNotFound(format!("{type_id:?}")).into()) + } -fn decode_variant_value<'scale, 'info, V: Visitor>( - data: &mut &'scale [u8], - ty_id: TypeId, - path: &'info Path, - ty: &'info TypeDefVariant, - types: &'info PortableRegistry, - visitor: V, -) -> Result, V::Error> { - let mut variant = Variant::new(data, path, ty, types)?; - let res = visitor.visit_variant(&mut variant, ty_id); + fn visit_composite(self, mut fields: Fields) -> Self::Value + where + Fields: FieldIter<'resolver, Self::TypeId>, + { + // guard against invalid compact types: only composites with 1 field can be compact encoded + if self.is_compact && fields.len() != 1 { + return Err(DecodeError::CannotDecodeCompactIntoType.into()); + } - // Skip over any bytes that the visitor chose not to decode: - variant.skip_decoding()?; - *data = variant.bytes_from_undecoded(); + let mut items = Composite::new(self.data, &mut fields, self.types, self.is_compact); + let res = self.visitor.visit_composite(&mut items, self.type_id); - res -} + // Skip over any bytes that the visitor chose not to decode: + items.skip_decoding()?; + *self.data = items.bytes_from_undecoded(); -fn decode_sequence_value<'scale, 'info, V: Visitor>( - data: &mut &'scale [u8], - ty_id: TypeId, - ty: &'info TypeDefSequence, - types: &'info PortableRegistry, - visitor: V, -) -> Result, V::Error> { - let mut items = Sequence::new(data, ty.type_param.id, types)?; - let res = visitor.visit_sequence(&mut items, ty_id); + res + } - // Skip over any bytes that the visitor chose not to decode: - items.skip_decoding()?; - *data = items.bytes_from_undecoded(); + fn visit_variant(self, variants: Var) -> Self::Value + where + Fields: FieldIter<'resolver, Self::TypeId> + 'resolver, + Var: VariantIter<'resolver, Fields>, + { + if self.is_compact { + return Err(DecodeError::CannotDecodeCompactIntoType.into()); + } - res -} + let mut variant = Variant::new(self.data, variants, self.types)?; + let res = self.visitor.visit_variant(&mut variant, self.type_id); -fn decode_array_value<'scale, 'info, V: Visitor>( - data: &mut &'scale [u8], - ty_id: TypeId, - ty: &'info TypeDefArray, - types: &'info PortableRegistry, - visitor: V, -) -> Result, V::Error> { - let len = ty.len as usize; - let mut arr = Array::new(data, ty.type_param.id, len, types); - let res = visitor.visit_array(&mut arr, ty_id); + // Skip over any bytes that the visitor chose not to decode: + variant.skip_decoding()?; + *self.data = variant.bytes_from_undecoded(); + + res + } - // Skip over any bytes that the visitor chose not to decode: - arr.skip_decoding()?; - *data = arr.bytes_from_undecoded(); + fn visit_sequence(self, inner_type_id: &'resolver Self::TypeId) -> Self::Value { + if self.is_compact { + return Err(DecodeError::CannotDecodeCompactIntoType.into()); + } - res -} + let mut items = Sequence::new(self.data, inner_type_id, self.types)?; + let res = self.visitor.visit_sequence(&mut items, self.type_id); -fn decode_tuple_value<'scale, 'info, V: Visitor>( - data: &mut &'scale [u8], - ty_id: TypeId, - ty: &'info TypeDefTuple, - types: &'info PortableRegistry, - visitor: V, - is_compact: bool, -) -> Result, V::Error> { - // guard against invalid compact types: only composites with 1 field can be compact encoded - if is_compact && ty.fields.len() != 1 { - return Err(DecodeError::CannotDecodeCompactIntoType(ty.clone().into()).into()); + // Skip over any bytes that the visitor chose not to decode: + items.skip_decoding()?; + *self.data = items.bytes_from_undecoded(); + + res } - let mut fields = ty.fields.iter().map(|f| Field::unnamed(f.id)); - let mut items = Tuple::new(data, &mut fields, types, is_compact); - let res = visitor.visit_tuple(&mut items, ty_id); + fn visit_array(self, inner_type_id: &'resolver Self::TypeId, len: usize) -> Self::Value { + if self.is_compact { + return Err(DecodeError::CannotDecodeCompactIntoType.into()); + } - // Skip over any bytes that the visitor chose not to decode: - items.skip_decoding()?; - *data = items.bytes_from_undecoded(); + let mut arr = Array::new(self.data, inner_type_id, len, self.types); + let res = self.visitor.visit_array(&mut arr, self.type_id); - res -} + // Skip over any bytes that the visitor chose not to decode: + arr.skip_decoding()?; + *self.data = arr.bytes_from_undecoded(); -fn decode_primitive_value<'scale, 'info, V: Visitor>( - data: &mut &'scale [u8], - ty_id: TypeId, - ty: &'info TypeDefPrimitive, - visitor: V, - is_compact: bool, -) -> Result, V::Error> { - fn decode_32_bytes<'scale>(data: &mut &'scale [u8]) -> Result<&'scale [u8; 32], DecodeError> { - // Pull an array from the data if we can, preserving the lifetime. - let arr: &'scale [u8; 32] = match (*data).try_into() { - Ok(arr) => arr, - Err(_) => return Err(DecodeError::NotEnoughInput), - }; - // If this works out, remember to shift data 32 bytes forward. - *data = &data[32..]; - Ok(arr) + res } - match ty { - TypeDefPrimitive::Bool => { - err_if_compact!(is_compact, ty); - let b = bool::decode(data).map_err(|e| e.into())?; - visitor.visit_bool(b, ty_id) + + fn visit_tuple(self, type_ids: TypeIds) -> Self::Value + where + TypeIds: ExactSizeIterator, + { + // guard against invalid compact types: only composites with 1 field can be compact encoded + if self.is_compact && type_ids.len() != 1 { + return Err(DecodeError::CannotDecodeCompactIntoType.into()); } - TypeDefPrimitive::Char => { - err_if_compact!(is_compact, ty); - // 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, ty_id) + + let mut fields = type_ids.map(Field::unnamed); + let mut items = Tuple::new(self.data, &mut fields, self.types, self.is_compact); + let res = self.visitor.visit_tuple(&mut items, self.type_id); + + // Skip over any bytes that the visitor chose not to decode: + items.skip_decoding()?; + *self.data = items.bytes_from_undecoded(); + + res + } + + fn visit_primitive(self, primitive: Primitive) -> Self::Value { + macro_rules! err_if_compact { + ($is_compact:expr) => { + if $is_compact { + return Err(DecodeError::CannotDecodeCompactIntoType.into()); + } + }; } - TypeDefPrimitive::Str => { - err_if_compact!(is_compact, ty); - // Avoid allocating; don't decode into a String. instead, pull the bytes - // and let the visitor decide whether to use them or not. - let mut s = Str::new(data)?; - // Since we aren't decoding here, shift our bytes along to after the str: - *data = s.bytes_after(); - visitor.visit_str(&mut s, ty_id) + + fn decode_32_bytes<'scale>( + data: &mut &'scale [u8], + ) -> Result<&'scale [u8; 32], DecodeError> { + // Pull an array from the data if we can, preserving the lifetime. + let arr: &'scale [u8; 32] = match (*data).try_into() { + Ok(arr) => arr, + Err(_) => return Err(DecodeError::NotEnoughInput), + }; + // If we successfully read the bytes, then advance the pointer past them. + *data = &data[32..]; + Ok(arr) } - TypeDefPrimitive::U8 => { - let n = if is_compact { - codec::Compact::::decode(data).map(|c| c.0) - } else { - u8::decode(data) + + let data = self.data; + let is_compact = self.is_compact; + let visitor = self.visitor; + let type_id = self.type_id; + + match primitive { + Primitive::Bool => { + err_if_compact!(is_compact); + let b = bool::decode(data).map_err(|e| e.into())?; + visitor.visit_bool(b, type_id) } - .map_err(Into::into)?; - visitor.visit_u8(n, ty_id) - } - TypeDefPrimitive::U16 => { - let n = if is_compact { - codec::Compact::::decode(data).map(|c| c.0) - } else { - u16::decode(data) + Primitive::Char => { + err_if_compact!(is_compact); + // 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, type_id) } - .map_err(Into::into)?; - visitor.visit_u16(n, ty_id) - } - TypeDefPrimitive::U32 => { - let n = if is_compact { - codec::Compact::::decode(data).map(|c| c.0) - } else { - u32::decode(data) + Primitive::Str => { + err_if_compact!(is_compact); + // Avoid allocating; don't decode into a String. instead, pull the bytes + // and let the visitor decide whether to use them or not. + let mut s = Str::new(data)?; + // Since we aren't decoding here, shift our bytes along to after the str: + *data = s.bytes_after(); + visitor.visit_str(&mut s, type_id) } - .map_err(Into::into)?; - visitor.visit_u32(n, ty_id) - } - TypeDefPrimitive::U64 => { - let n = if is_compact { - codec::Compact::::decode(data).map(|c| c.0) - } else { - u64::decode(data) + Primitive::U8 => { + let n = if is_compact { + codec::Compact::::decode(data).map(|c| c.0) + } else { + u8::decode(data) + } + .map_err(Into::into)?; + visitor.visit_u8(n, type_id) } - .map_err(Into::into)?; - visitor.visit_u64(n, ty_id) - } - TypeDefPrimitive::U128 => { - let n = if is_compact { - codec::Compact::::decode(data).map(|c| c.0) - } else { - u128::decode(data) + Primitive::U16 => { + let n = if is_compact { + codec::Compact::::decode(data).map(|c| c.0) + } else { + u16::decode(data) + } + .map_err(Into::into)?; + visitor.visit_u16(n, type_id) + } + Primitive::U32 => { + let n = if is_compact { + codec::Compact::::decode(data).map(|c| c.0) + } else { + u32::decode(data) + } + .map_err(Into::into)?; + visitor.visit_u32(n, type_id) + } + Primitive::U64 => { + let n = if is_compact { + codec::Compact::::decode(data).map(|c| c.0) + } else { + u64::decode(data) + } + .map_err(Into::into)?; + visitor.visit_u64(n, type_id) + } + Primitive::U128 => { + let n = if is_compact { + codec::Compact::::decode(data).map(|c| c.0) + } else { + u128::decode(data) + } + .map_err(Into::into)?; + visitor.visit_u128(n, type_id) + } + Primitive::U256 => { + err_if_compact!(is_compact); + let arr = decode_32_bytes(data)?; + visitor.visit_u256(arr, type_id) + } + Primitive::I8 => { + err_if_compact!(is_compact); + let n = i8::decode(data).map_err(|e| e.into())?; + visitor.visit_i8(n, type_id) + } + Primitive::I16 => { + err_if_compact!(is_compact); + let n = i16::decode(data).map_err(|e| e.into())?; + visitor.visit_i16(n, type_id) + } + Primitive::I32 => { + err_if_compact!(is_compact); + let n = i32::decode(data).map_err(|e| e.into())?; + visitor.visit_i32(n, type_id) + } + Primitive::I64 => { + err_if_compact!(is_compact); + let n = i64::decode(data).map_err(|e| e.into())?; + visitor.visit_i64(n, type_id) + } + Primitive::I128 => { + err_if_compact!(is_compact); + let n = i128::decode(data).map_err(|e| e.into())?; + visitor.visit_i128(n, type_id) + } + Primitive::I256 => { + err_if_compact!(is_compact); + let arr = decode_32_bytes(data)?; + visitor.visit_i256(arr, type_id) } - .map_err(Into::into)?; - visitor.visit_u128(n, ty_id) - } - TypeDefPrimitive::U256 => { - err_if_compact!(is_compact, *ty); - let arr = decode_32_bytes(data)?; - visitor.visit_u256(arr, ty_id) - } - TypeDefPrimitive::I8 => { - err_if_compact!(is_compact, ty); - let n = i8::decode(data).map_err(|e| e.into())?; - visitor.visit_i8(n, ty_id) - } - TypeDefPrimitive::I16 => { - err_if_compact!(is_compact, ty); - let n = i16::decode(data).map_err(|e| e.into())?; - visitor.visit_i16(n, ty_id) - } - TypeDefPrimitive::I32 => { - err_if_compact!(is_compact, ty); - let n = i32::decode(data).map_err(|e| e.into())?; - visitor.visit_i32(n, ty_id) - } - TypeDefPrimitive::I64 => { - err_if_compact!(is_compact, ty); - let n = i64::decode(data).map_err(|e| e.into())?; - visitor.visit_i64(n, ty_id) - } - TypeDefPrimitive::I128 => { - err_if_compact!(is_compact, ty); - let n = i128::decode(data).map_err(|e| e.into())?; - visitor.visit_i128(n, ty_id) - } - TypeDefPrimitive::I256 => { - err_if_compact!(is_compact, ty); - let arr = decode_32_bytes(data)?; - visitor.visit_i256(arr, ty_id) } } -} -fn decode_bit_sequence_value<'scale, 'info, V: Visitor>( - data: &mut &'scale [u8], - ty_id: TypeId, - ty: &'info TypeDefBitSequence, - types: &'info PortableRegistry, - visitor: V, -) -> Result, V::Error> { - use scale_bits::Format; + fn visit_compact(self, inner_type_id: &'resolver Self::TypeId) -> Self::Value { + decode_with_visitor_maybe_compact(self.data, inner_type_id, self.types, self.visitor, true) + } + + fn visit_bit_sequence( + self, + store_format: BitsStoreFormat, + order_format: BitsOrderFormat, + ) -> Self::Value { + if self.is_compact { + return Err(DecodeError::CannotDecodeCompactIntoType.into()); + } - let format = Format::from_metadata(ty, types).map_err(DecodeError::BitSequenceError)?; - let mut bitseq = BitSequence::new(format, data); - let res = visitor.visit_bitsequence(&mut bitseq, ty_id); + let format = scale_bits::Format::new(store_format, order_format); + let mut bitseq = BitSequence::new(format, self.data); + let res = self.visitor.visit_bitsequence(&mut bitseq, self.type_id); - // Move to the bytes after the bit sequence. - *data = bitseq.bytes_after()?; + // Move to the bytes after the bit sequence. + *self.data = bitseq.bytes_after()?; - res + res + } } diff --git a/scale-decode/src/visitor/mod.rs b/scale-decode/src/visitor/mod.rs index 2bccd30..7febe76 100644 --- a/scale-decode/src/visitor/mod.rs +++ b/scale-decode/src/visitor/mod.rs @@ -18,21 +18,28 @@ mod decode; pub mod types; -use scale_info::form::PortableForm; +use alloc::string::String; +use core::marker::PhantomData; +use scale_type_resolver::TypeResolver; use types::*; pub use decode::decode_with_visitor; pub(crate) use decode::decode_with_visitor_maybe_compact; +/// Return the type ID type of some [`Visitor`]. +pub type TypeIdFor = <::TypeResolver as TypeResolver>::TypeId; + /// An implementation of the [`Visitor`] trait can be passed to the [`decode_with_visitor()`] /// function, and is handed back values as they are encountered. It's up to the implementation /// to decide what to do with these values. pub trait Visitor: Sized { /// The type of the value to hand back from the [`decode_with_visitor()`] function. - type Value<'scale, 'info>; + type Value<'scale, 'resolver>; /// The error type (which we must be able to convert a combination of [`Self`] and [`DecodeError`]s /// into, to handle any internal errors that crop up trying to decode things). type Error: From; + /// The thing we'll use to resolve type IDs into concrete types. + type TypeResolver: TypeResolver; /// This method is called immediately upon running [`decode_with_visitor()`]. By default we ignore /// this call and return our visitor back (ie [`DecodeAsTypeResult::Skipped(visitor)`]). If you choose to @@ -44,191 +51,191 @@ pub trait Visitor: Sized { /// Unlike the other `visit_*` methods, it is completely up to the implementor to decode and advance the /// bytes in a sensible way, and thus also possible for the implementor to screw this up. As a result, /// it's suggested that you don't implement this unless you know what you're doing. - fn unchecked_decode_as_type<'scale, 'info>( + fn unchecked_decode_as_type<'scale, 'resolver>( self, _input: &mut &'scale [u8], - _type_id: TypeId, - _types: &'info scale_info::PortableRegistry, - ) -> DecodeAsTypeResult, Self::Error>> { + _type_id: &TypeIdFor, + _types: &'resolver Self::TypeResolver, + ) -> DecodeAsTypeResult, Self::Error>> { DecodeAsTypeResult::Skipped(self) } /// This is called when a visitor function that you've not provided an implementation is called. /// You are provided an enum value corresponding to the function call, and can decide what to return /// in this case. The default is to return an error to announce the unexpected value. - fn visit_unexpected<'scale, 'info>( + fn visit_unexpected<'scale, 'resolver>( self, unexpected: Unexpected, - ) -> Result, Self::Error> { + ) -> Result, Self::Error> { Err(DecodeError::Unexpected(unexpected).into()) } /// Called when a bool is seen in the input bytes. - fn visit_bool<'scale, 'info>( + fn visit_bool<'scale, 'resolver>( self, _value: bool, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { self.visit_unexpected(Unexpected::Bool) } /// Called when a char is seen in the input bytes. - fn visit_char<'scale, 'info>( + fn visit_char<'scale, 'resolver>( self, _value: char, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { self.visit_unexpected(Unexpected::Char) } /// Called when a u8 is seen in the input bytes. - fn visit_u8<'scale, 'info>( + fn visit_u8<'scale, 'resolver>( self, _value: u8, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { self.visit_unexpected(Unexpected::U8) } /// Called when a u16 is seen in the input bytes. - fn visit_u16<'scale, 'info>( + fn visit_u16<'scale, 'resolver>( self, _value: u16, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { self.visit_unexpected(Unexpected::U16) } /// Called when a u32 is seen in the input bytes. - fn visit_u32<'scale, 'info>( + fn visit_u32<'scale, 'resolver>( self, _value: u32, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { self.visit_unexpected(Unexpected::U32) } /// Called when a u64 is seen in the input bytes. - fn visit_u64<'scale, 'info>( + fn visit_u64<'scale, 'resolver>( self, _value: u64, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { self.visit_unexpected(Unexpected::U64) } /// Called when a u128 is seen in the input bytes. - fn visit_u128<'scale, 'info>( + fn visit_u128<'scale, 'resolver>( self, _value: u128, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { self.visit_unexpected(Unexpected::U128) } /// Called when a u256 is seen in the input bytes. - fn visit_u256<'info>( + fn visit_u256<'scale, 'resolver>( self, - _value: &'_ [u8; 32], - _type_id: TypeId, - ) -> Result, Self::Error> { + _value: &'scale [u8; 32], + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { self.visit_unexpected(Unexpected::U256) } /// Called when an i8 is seen in the input bytes. - fn visit_i8<'scale, 'info>( + fn visit_i8<'scale, 'resolver>( self, _value: i8, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { self.visit_unexpected(Unexpected::I8) } /// Called when an i16 is seen in the input bytes. - fn visit_i16<'scale, 'info>( + fn visit_i16<'scale, 'resolver>( self, _value: i16, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { self.visit_unexpected(Unexpected::I16) } /// Called when an i32 is seen in the input bytes. - fn visit_i32<'scale, 'info>( + fn visit_i32<'scale, 'resolver>( self, _value: i32, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { self.visit_unexpected(Unexpected::I32) } /// Called when an i64 is seen in the input bytes. - fn visit_i64<'scale, 'info>( + fn visit_i64<'scale, 'resolver>( self, _value: i64, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { self.visit_unexpected(Unexpected::I64) } /// Called when an i128 is seen in the input bytes. - fn visit_i128<'scale, 'info>( + fn visit_i128<'scale, 'resolver>( self, _value: i128, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { self.visit_unexpected(Unexpected::I128) } /// Called when an i256 is seen in the input bytes. - fn visit_i256<'info>( + fn visit_i256<'scale, 'resolver>( self, - _value: &'_ [u8; 32], - _type_id: TypeId, - ) -> Result, Self::Error> { + _value: &'scale [u8; 32], + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { self.visit_unexpected(Unexpected::I256) } /// Called when a sequence of values is seen in the input bytes. - fn visit_sequence<'scale, 'info>( + fn visit_sequence<'scale, 'resolver>( self, - _value: &mut Sequence<'scale, 'info>, - _type_id: TypeId, - ) -> Result, Self::Error> { + _value: &mut Sequence<'scale, 'resolver, Self::TypeResolver>, + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { self.visit_unexpected(Unexpected::Sequence) } /// Called when a composite value is seen in the input bytes. - fn visit_composite<'scale, 'info>( + fn visit_composite<'scale, 'resolver>( self, - _value: &mut Composite<'scale, 'info>, - _type_id: TypeId, - ) -> Result, Self::Error> { + _value: &mut Composite<'scale, 'resolver, Self::TypeResolver>, + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { self.visit_unexpected(Unexpected::Composite) } /// Called when a tuple of values is seen in the input bytes. - fn visit_tuple<'scale, 'info>( + fn visit_tuple<'scale, 'resolver>( self, - _value: &mut Tuple<'scale, 'info>, - _type_id: TypeId, - ) -> Result, Self::Error> { + _value: &mut Tuple<'scale, 'resolver, Self::TypeResolver>, + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { self.visit_unexpected(Unexpected::Tuple) } /// Called when a string value is seen in the input bytes. - fn visit_str<'scale, 'info>( + fn visit_str<'scale, 'resolver>( self, _value: &mut Str<'scale>, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { self.visit_unexpected(Unexpected::Str) } /// Called when a variant is seen in the input bytes. - fn visit_variant<'scale, 'info>( + fn visit_variant<'scale, 'resolver>( self, - _value: &mut Variant<'scale, 'info>, - _type_id: TypeId, - ) -> Result, Self::Error> { + _value: &mut Variant<'scale, 'resolver, Self::TypeResolver>, + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { self.visit_unexpected(Unexpected::Variant) } /// Called when an array is seen in the input bytes. - fn visit_array<'scale, 'info>( + fn visit_array<'scale, 'resolver>( self, - _value: &mut Array<'scale, 'info>, - _type_id: TypeId, - ) -> Result, Self::Error> { + _value: &mut Array<'scale, 'resolver, Self::TypeResolver>, + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { self.visit_unexpected(Unexpected::Array) } /// Called when a bit sequence is seen in the input bytes. - fn visit_bitsequence<'scale, 'info>( + fn visit_bitsequence<'scale, 'resolver>( self, _value: &mut BitSequence<'scale>, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { self.visit_unexpected(Unexpected::Bitsequence) } } @@ -236,13 +243,15 @@ pub trait Visitor: Sized { /// An error decoding SCALE bytes. #[derive(Debug, Clone, PartialEq, Eq, derive_more::From, derive_more::Display)] pub enum DecodeError { - /// We ran into an error trying to decode a bit sequence. - #[from] - #[display(fmt = "Cannot decode bit sequence: {_0}")] - BitSequenceError(BitSequenceError), + /// Type ID was not found + #[display(fmt = "Could not find type with ID '{_0:?}'")] + TypeIdNotFound(String), + /// A low level error trying to resolve a type. + #[display(fmt = "Failed to resolve type: {_0}")] + TypeResolvingError(String), /// The type we're trying to decode is supposed to be compact encoded, but that is not possible. - #[display(fmt = "Could not decode compact encoded type into {_0:?}")] - CannotDecodeCompactIntoType(scale_info::Type), + #[display(fmt = "Could not decode compact encoded type: compact types can only have 1 field")] + CannotDecodeCompactIntoType, /// Failure to decode bytes into a string. #[from] #[display(fmt = "Could not decode string: {_0}")] @@ -254,14 +263,11 @@ pub enum DecodeError { #[display(fmt = "Ran out of data during decoding")] NotEnoughInput, /// We found a variant that does not match with any in the type we're trying to decode from. - #[display(fmt = "Could not find variant with index {_0} in {_1:?}")] - VariantNotFound(u8, scale_info::TypeDefVariant), + #[display(fmt = "Could not find variant with index {_0}")] + VariantNotFound(u8), /// Some error emitted from a [`codec::Decode`] impl. #[from] CodecError(codec::Error), - /// We could not find the type given in the type registry provided. - #[display(fmt = "Cannot find type with ID {_0}")] - TypeIdNotFound(u32), /// This is returned by default if a visitor function is not implemented. #[display(fmt = "Unexpected type {_0}")] Unexpected(Unexpected), @@ -348,32 +354,40 @@ impl DecodeAsTypeResult { /// This is implemented for visitor related types which have a `decode_item` method, /// and allows you to generically talk about decoding unnamed items. -pub trait DecodeItemIterator<'scale, 'info> { +pub trait DecodeItemIterator<'scale, 'resolver, R: TypeResolver> { /// Use a visitor to decode a single item. - fn decode_item( + fn decode_item>( &mut self, visitor: V, - ) -> Option, V::Error>>; + ) -> Option, V::Error>>; } -/// An error that can occur trying to decode a bit sequence. -pub type BitSequenceError = scale_bits::scale::format::FromMetadataError; +/// A [`Visitor`] implementation that just ignores all of the bytes. +pub struct IgnoreVisitor(PhantomData); -/// The ID of the type being decoded. -#[derive(Clone, Copy, Debug, Default)] -pub struct TypeId(pub u32); +impl Default for IgnoreVisitor { + fn default() -> Self { + Self::new() + } +} -/// A [`Visitor`] implementation that just ignores all of the bytes. -pub struct IgnoreVisitor; -impl Visitor for IgnoreVisitor { - type Value<'scale, 'info> = (); +impl IgnoreVisitor { + /// Construct a new [`IgnoreVisitor`]. + pub fn new() -> Self { + IgnoreVisitor(PhantomData) + } +} + +impl Visitor for IgnoreVisitor { + type Value<'scale, 'resolver> = (); type Error = DecodeError; + type TypeResolver = R; // Whatever the value we visit is, just ignore it. - fn visit_unexpected<'scale, 'info>( + fn visit_unexpected<'scale, 'resolver>( self, _unexpected: Unexpected, - ) -> Result, Self::Error> { + ) -> Result, Self::Error> { Ok(()) } } @@ -392,24 +406,23 @@ impl Visitor for VisitorWithCrateError where V::Error: Into, { - type Value<'scale, 'info> = V::Value<'scale, 'info>; + type Value<'scale, 'resolver> = V::Value<'scale, 'resolver>; type Error = crate::Error; + type TypeResolver = V::TypeResolver; - fn unchecked_decode_as_type<'scale, 'info>( + fn unchecked_decode_as_type<'scale, 'resolver>( self, input: &mut &'scale [u8], - type_id: TypeId, - types: &'info scale_info::PortableRegistry, - ) -> DecodeAsTypeResult, Self::Error>> { - let res = decode_with_visitor(input, type_id.0, types, self.0).map_err(Into::into); + type_id: &TypeIdFor, + types: &'resolver Self::TypeResolver, + ) -> DecodeAsTypeResult, Self::Error>> { + let res = decode_with_visitor(input, type_id, types, self.0).map_err(Into::into); DecodeAsTypeResult::Decoded(res) } } #[cfg(test)] mod test { - use crate::visitor::TypeId; - use super::*; use alloc::borrow::ToOwned; use alloc::string::{String, ToString}; @@ -445,187 +458,200 @@ mod test { BitSequence(scale_bits::Bits), } - #[derive(Clone, Copy)] - struct ValueVisitor; - impl Visitor for ValueVisitor { - type Value<'scale, 'info> = Value; + struct ValueVisitor(PhantomData); + impl Clone for ValueVisitor { + fn clone(&self) -> Self { + *self + } + } + impl Copy for ValueVisitor {} + + impl ValueVisitor { + pub fn new() -> Self { + Self(PhantomData) + } + } + + impl Visitor for ValueVisitor { + type Value<'scale, 'resolver> = Value; type Error = DecodeError; + type TypeResolver = R; - fn visit_bool<'scale, 'info>( + fn visit_bool<'scale, 'resolver>( self, value: bool, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::Bool(value)) } - fn visit_char<'scale, 'info>( + fn visit_char<'scale, 'resolver>( self, value: char, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::Char(value)) } - fn visit_u8<'scale, 'info>( + fn visit_u8<'scale, 'resolver>( self, value: u8, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::U8(value)) } - fn visit_u16<'scale, 'info>( + fn visit_u16<'scale, 'resolver>( self, value: u16, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::U16(value)) } - fn visit_u32<'scale, 'info>( + fn visit_u32<'scale, 'resolver>( self, value: u32, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::U32(value)) } - fn visit_u64<'scale, 'info>( + fn visit_u64<'scale, 'resolver>( self, value: u64, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::U64(value)) } - fn visit_u128<'scale, 'info>( + fn visit_u128<'scale, 'resolver>( self, value: u128, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::U128(value)) } - fn visit_u256<'info>( + fn visit_u256<'scale, 'resolver>( self, - value: &'_ [u8; 32], - _type_id: TypeId, - ) -> Result, Self::Error> { + value: &'scale [u8; 32], + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::U256(*value)) } - fn visit_i8<'scale, 'info>( + fn visit_i8<'scale, 'resolver>( self, value: i8, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::I8(value)) } - fn visit_i16<'scale, 'info>( + fn visit_i16<'scale, 'resolver>( self, value: i16, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::I16(value)) } - fn visit_i32<'scale, 'info>( + fn visit_i32<'scale, 'resolver>( self, value: i32, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::I32(value)) } - fn visit_i64<'scale, 'info>( + fn visit_i64<'scale, 'resolver>( self, value: i64, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::I64(value)) } - fn visit_i128<'scale, 'info>( + fn visit_i128<'scale, 'resolver>( self, value: i128, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::I128(value)) } - fn visit_i256<'info>( + fn visit_i256<'scale, 'resolver>( self, - value: &'_ [u8; 32], - _type_id: TypeId, - ) -> Result, Self::Error> { + value: &'scale [u8; 32], + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::I256(*value)) } - fn visit_sequence<'scale, 'info>( + fn visit_sequence<'scale, 'resolver>( self, - value: &mut Sequence<'scale, 'info>, - _type_id: TypeId, - ) -> Result, Self::Error> { + value: &mut Sequence<'scale, 'resolver, Self::TypeResolver>, + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { let mut vals = vec![]; - while let Some(val) = value.decode_item(ValueVisitor) { + while let Some(val) = value.decode_item(ValueVisitor::new()) { let val = val?; vals.push(val); } Ok(Value::Sequence(vals)) } - fn visit_composite<'scale, 'info>( + fn visit_composite<'scale, 'resolver>( self, - value: &mut Composite<'scale, 'info>, - _type_id: TypeId, - ) -> Result, Self::Error> { + value: &mut Composite<'scale, 'resolver, Self::TypeResolver>, + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { let mut vals = vec![]; for item in value.by_ref() { let item = item?; - let val = item.decode_with_visitor(ValueVisitor)?; + let val = item.decode_with_visitor(ValueVisitor::new())?; let name = item.name().unwrap_or("").to_owned(); vals.push((name, val)); } Ok(Value::Composite(vals)) } - fn visit_tuple<'scale, 'info>( + fn visit_tuple<'scale, 'resolver>( self, - value: &mut Tuple<'scale, 'info>, - _type_id: TypeId, - ) -> Result, Self::Error> { + value: &mut Tuple<'scale, 'resolver, Self::TypeResolver>, + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { let mut vals = vec![]; - while let Some(val) = value.decode_item(ValueVisitor) { + while let Some(val) = value.decode_item(ValueVisitor::new()) { let val = val?; vals.push(val); } Ok(Value::Tuple(vals)) } - fn visit_str<'scale, 'info>( + fn visit_str<'scale, 'resolver>( self, value: &mut Str<'scale>, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { Ok(Value::Str(value.as_str()?.to_owned())) } - fn visit_variant<'scale, 'info>( + fn visit_variant<'scale, 'resolver>( self, - value: &mut Variant<'scale, 'info>, - _type_id: TypeId, - ) -> Result, Self::Error> { + value: &mut Variant<'scale, 'resolver, Self::TypeResolver>, + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { let mut vals = vec![]; let fields = value.fields(); for item in fields.by_ref() { let item = item?; - let val = item.decode_with_visitor(ValueVisitor)?; + let val = item.decode_with_visitor(ValueVisitor::new())?; let name = item.name().unwrap_or("").to_owned(); vals.push((name, val)); } Ok(Value::Variant(value.name().to_owned(), vals)) } - fn visit_array<'scale, 'info>( + fn visit_array<'scale, 'resolver>( self, - value: &mut Array<'scale, 'info>, - _type_id: TypeId, - ) -> Result, Self::Error> { + value: &mut Array<'scale, 'resolver, Self::TypeResolver>, + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { let mut vals = vec![]; - while let Some(val) = value.decode_item(ValueVisitor) { + while let Some(val) = value.decode_item(ValueVisitor::new()) { let val = val?; vals.push(val); } Ok(Value::Array(vals)) } - fn visit_bitsequence<'scale, 'info>( + fn visit_bitsequence<'scale, 'resolver>( self, value: &mut BitSequence<'scale>, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { let bools: Result = value.decode()?.collect(); Ok(Value::BitSequence(bools?)) } @@ -647,7 +673,7 @@ mod test { fn encode_decode_check_explicit_info< Ty: scale_info::TypeInfo + 'static, T: Encode, - V: for<'s, 'i> Visitor = Value, Error = E>, + V: for<'s, 'i> Visitor = Value, Error = E, TypeResolver = PortableRegistry>, E: core::fmt::Debug, >( val: T, @@ -658,7 +684,7 @@ mod test { let (id, types) = make_type::(); let bytes = &mut &*encoded; let val = - decode_with_visitor(bytes, id, &types, visitor).expect("decoding should not error"); + decode_with_visitor(bytes, &id, &types, visitor).expect("decoding should not error"); assert_eq!(bytes.len(), 0, "Decoding should consume all bytes"); assert_eq!(val, expected); @@ -666,7 +692,7 @@ mod test { fn encode_decode_check_with_visitor< T: Encode + scale_info::TypeInfo + 'static, - V: for<'s, 'i> Visitor = Value, Error = E>, + V: for<'s, 'i> Visitor = Value, Error = E, TypeResolver = PortableRegistry>, E: core::fmt::Debug, >( val: T, @@ -677,13 +703,13 @@ mod test { } fn encode_decode_check(val: T, expected: Value) { - encode_decode_check_explicit_info::(val, expected, ValueVisitor); + encode_decode_check_explicit_info::(val, expected, ValueVisitor::new()); } #[test] fn decode_with_root_error_wrapper_works() { use crate::visitor::VisitorWithCrateError; - let visitor = VisitorWithCrateError(ValueVisitor); + let visitor = VisitorWithCrateError(ValueVisitor::new()); encode_decode_check_with_visitor(123u8, Value::U8(123), visitor); encode_decode_check_with_visitor(123u16, Value::U16(123), visitor); @@ -726,7 +752,7 @@ mod test { encode_decode_check_explicit_info::( 'c' as u32, Value::Char('c'), - ValueVisitor, + ValueVisitor::new(), ); encode_decode_check("Hello there", Value::Str("Hello there".to_owned())); encode_decode_check("Hello there".to_string(), Value::Str("Hello there".to_owned())); @@ -939,14 +965,15 @@ mod test { // This can just zero-copy decode a string: struct ZeroCopyStrVisitor; impl Visitor for ZeroCopyStrVisitor { - type Value<'scale, 'info> = &'scale str; + type Value<'scale, 'resolver> = &'scale str; type Error = DecodeError; + type TypeResolver = PortableRegistry; - fn visit_str<'scale, 'info>( + fn visit_str<'scale, 'resolver>( self, value: &mut Str<'scale>, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { value.as_str() } } @@ -954,14 +981,15 @@ mod test { // This can zero-copy decode the pair of strings we have as input: struct ZeroCopyPairVisitor; impl Visitor for ZeroCopyPairVisitor { - type Value<'scale, 'info> = (&'scale str, &'scale str); + type Value<'scale, 'resolver> = (&'scale str, &'scale str); type Error = DecodeError; + type TypeResolver = PortableRegistry; - fn visit_tuple<'scale, 'info>( + fn visit_tuple<'scale, 'resolver>( self, - value: &mut Tuple<'scale, 'info>, - _type_id: TypeId, - ) -> Result, Self::Error> { + value: &mut Tuple<'scale, 'resolver, Self::TypeResolver>, + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { let fst = value.decode_item(ZeroCopyStrVisitor).unwrap()?; let snd = value.decode_item(ZeroCopyStrVisitor).unwrap()?; Ok((fst, snd)) @@ -970,7 +998,7 @@ mod test { let (ty_id, types) = make_type::<(&str, &str)>(); let decoded = - decode_with_visitor(&mut &*input_encoded, ty_id, &types, ZeroCopyPairVisitor).unwrap(); + decode_with_visitor(&mut &*input_encoded, &ty_id, &types, ZeroCopyPairVisitor).unwrap(); assert_eq!(decoded, ("hello", "world")); } @@ -990,14 +1018,15 @@ mod test { // This can just zero-copy decode a string: struct ZeroCopyStrVisitor; impl Visitor for ZeroCopyStrVisitor { - type Value<'scale, 'info> = &'scale str; + type Value<'scale, 'resolver> = &'scale str; type Error = DecodeError; + type TypeResolver = PortableRegistry; - fn visit_str<'scale, 'info>( + fn visit_str<'scale, 'resolver>( self, value: &mut Str<'scale>, - _type_id: TypeId, - ) -> Result, Self::Error> { + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { value.as_str() } } @@ -1005,15 +1034,17 @@ mod test { // This zero-copy decodes a composite into map of strings: struct ZeroCopyMapVisitor; impl Visitor for ZeroCopyMapVisitor { - type Value<'scale, 'info> = alloc::collections::BTreeMap<&'info str, &'scale str>; + type Value<'scale, 'resolver> = + alloc::collections::BTreeMap<&'resolver str, &'scale str>; type Error = DecodeError; + type TypeResolver = PortableRegistry; - fn visit_composite<'scale, 'info>( + fn visit_composite<'scale, 'resolver>( self, - value: &mut Composite<'scale, 'info>, - _type_id: TypeId, - ) -> Result, Self::Error> { - let mut vals = alloc::collections::BTreeMap::<&'info str, &'scale str>::new(); + value: &mut Composite<'scale, 'resolver, Self::TypeResolver>, + _type_id: &TypeIdFor, + ) -> Result, Self::Error> { + let mut vals = alloc::collections::BTreeMap::<&'resolver str, &'scale str>::new(); for item in value { let item = item?; let Some(key) = item.name() else { continue }; @@ -1027,7 +1058,7 @@ mod test { // Decode and check: let (ty_id, types) = make_type::(); let decoded = - decode_with_visitor(&mut &*input_encoded, ty_id, &types, ZeroCopyMapVisitor).unwrap(); + decode_with_visitor(&mut &*input_encoded, &ty_id, &types, ZeroCopyMapVisitor).unwrap(); assert_eq!(decoded, BTreeMap::from_iter([("hello", "hi"), ("world", "planet")])); } @@ -1041,37 +1072,39 @@ mod test { // that we can successfully "bail out". struct BailOutVisitor; impl Visitor for BailOutVisitor { - type Value<'scale, 'info> = (&'scale [u8], u32); + type Value<'scale, 'resolver> = (&'scale [u8], u32); type Error = DecodeError; + type TypeResolver = PortableRegistry; - fn unchecked_decode_as_type<'scale, 'info>( + fn unchecked_decode_as_type<'scale, 'resolver>( self, input: &mut &'scale [u8], - type_id: TypeId, - _types: &'info scale_info::PortableRegistry, - ) -> DecodeAsTypeResult, Self::Error>> + type_id: &u32, + _types: &'resolver scale_info::PortableRegistry, + ) -> DecodeAsTypeResult, Self::Error>> { - DecodeAsTypeResult::Decoded(Ok((*input, type_id.0))) + DecodeAsTypeResult::Decoded(Ok((*input, *type_id))) } } let decoded = - decode_with_visitor(&mut &*input_encoded, ty_id, &types, BailOutVisitor).unwrap(); + decode_with_visitor(&mut &*input_encoded, &ty_id, &types, BailOutVisitor).unwrap(); assert_eq!(decoded, (&*input_encoded, ty_id)); // We can also use this functionality to "fall-back" to a Decode impl // (though obviously with the caveat that this may be incorrect). struct CodecDecodeVisitor(core::marker::PhantomData); impl Visitor for CodecDecodeVisitor { - type Value<'scale, 'info> = T; + type Value<'scale, 'resolver> = T; type Error = DecodeError; + type TypeResolver = PortableRegistry; - fn unchecked_decode_as_type<'scale, 'info>( + fn unchecked_decode_as_type<'scale, 'resolver>( self, input: &mut &'scale [u8], - _type_id: TypeId, - _types: &'info scale_info::PortableRegistry, - ) -> DecodeAsTypeResult, Self::Error>> + _type_id: &TypeIdFor, + _types: &'resolver scale_info::PortableRegistry, + ) -> DecodeAsTypeResult, Self::Error>> { DecodeAsTypeResult::Decoded(T::decode(input).map_err(|e| e.into())) } @@ -1079,7 +1112,7 @@ mod test { let decoded: (String, String) = decode_with_visitor( &mut &*input_encoded, - ty_id, + &ty_id, &types, CodecDecodeVisitor(core::marker::PhantomData), ) diff --git a/scale-decode/src/visitor/types/array.rs b/scale-decode/src/visitor/types/array.rs index ba7a418..2ad49a8 100644 --- a/scale-decode/src/visitor/types/array.rs +++ b/scale-decode/src/visitor/types/array.rs @@ -17,31 +17,31 @@ use crate::{ visitor::{DecodeError, IgnoreVisitor, Visitor}, DecodeAsType, }; -use scale_info::PortableRegistry; +use scale_type_resolver::TypeResolver; /// This enables a visitor to decode items from an array type. -pub struct Array<'scale, 'info> { +pub struct Array<'scale, 'resolver, R: TypeResolver> { bytes: &'scale [u8], item_bytes: &'scale [u8], - type_id: u32, - types: &'info PortableRegistry, + type_id: &'resolver R::TypeId, + types: &'resolver R, remaining: usize, } -impl<'scale, 'info> Array<'scale, 'info> { +impl<'scale, 'resolver, R: TypeResolver> Array<'scale, 'resolver, R> { pub(crate) fn new( bytes: &'scale [u8], - type_id: u32, + type_id: &'resolver R::TypeId, len: usize, - types: &'info PortableRegistry, - ) -> Array<'scale, 'info> { + types: &'resolver R, + ) -> Array<'scale, 'resolver, R> { Array { bytes, item_bytes: bytes, type_id, types, remaining: len } } /// Skip over all bytes associated with this array. After calling this, /// [`Self::bytes_from_undecoded()`] will represent the bytes after this array. pub fn skip_decoding(&mut self) -> Result<(), DecodeError> { while self.remaining > 0 { - self.decode_item(IgnoreVisitor).transpose()?; + self.decode_item(IgnoreVisitor::::new()).transpose()?; } Ok(()) } @@ -63,10 +63,10 @@ impl<'scale, 'info> Array<'scale, 'info> { self.remaining == 0 } /// Decode an item from the array by providing a visitor to handle it. - pub fn decode_item( + pub fn decode_item>( &mut self, visitor: V, - ) -> Option, V::Error>> { + ) -> Option, V::Error>> { if self.remaining == 0 { return None; } @@ -82,14 +82,14 @@ impl<'scale, 'info> Array<'scale, 'info> { } // Iterating returns a representation of each field in the tuple type. -impl<'scale, 'info> Iterator for Array<'scale, 'info> { - type Item = Result, DecodeError>; +impl<'scale, 'resolver, R: TypeResolver> Iterator for Array<'scale, 'resolver, R> { + type Item = Result, DecodeError>; fn next(&mut self) -> Option { // Record details we need before we decode and skip over the thing: let num_bytes_before = self.item_bytes.len(); let item_bytes = self.item_bytes; - if let Err(e) = self.decode_item(IgnoreVisitor)? { + if let Err(e) = self.decode_item(IgnoreVisitor::::new())? { return Some(Err(e)); }; @@ -102,27 +102,33 @@ impl<'scale, 'info> Iterator for Array<'scale, 'info> { } /// A single item in the array. -#[derive(Copy, Clone)] -pub struct ArrayItem<'scale, 'info> { +pub struct ArrayItem<'scale, 'resolver, R: TypeResolver> { bytes: &'scale [u8], - type_id: u32, - types: &'info PortableRegistry, + type_id: &'resolver R::TypeId, + types: &'resolver R, } -impl<'scale, 'info> ArrayItem<'scale, 'info> { +impl<'scale, 'resolver, R: TypeResolver> Copy for ArrayItem<'scale, 'resolver, R> {} +impl<'scale, 'resolver, R: TypeResolver> Clone for ArrayItem<'scale, 'resolver, R> { + fn clone(&self) -> Self { + *self + } +} + +impl<'scale, 'resolver, R: TypeResolver> ArrayItem<'scale, 'resolver, R> { /// The bytes associated with this item. pub fn bytes(&self) -> &'scale [u8] { self.bytes } /// The type ID associated with this item. - pub fn type_id(&self) -> u32 { + pub fn type_id(&self) -> &R::TypeId { self.type_id } /// Decode this item using a visitor. - pub fn decode_with_visitor( + pub fn decode_with_visitor>( &self, visitor: V, - ) -> Result, V::Error> { + ) -> Result, V::Error> { crate::visitor::decode_with_visitor(&mut &*self.bytes, self.type_id, self.types, visitor) } /// Decode this item into a specific type via [`DecodeAsType`]. @@ -131,11 +137,13 @@ impl<'scale, 'info> ArrayItem<'scale, 'info> { } } -impl<'scale, 'info> crate::visitor::DecodeItemIterator<'scale, 'info> for Array<'scale, 'info> { - fn decode_item<'a, V: Visitor>( +impl<'scale, 'resolver, R: TypeResolver> crate::visitor::DecodeItemIterator<'scale, 'resolver, R> + for Array<'scale, 'resolver, R> +{ + fn decode_item>( &mut self, visitor: V, - ) -> Option, V::Error>> { + ) -> Option, V::Error>> { self.decode_item(visitor) } } diff --git a/scale-decode/src/visitor/types/composite.rs b/scale-decode/src/visitor/types/composite.rs index a1fbacc..4d3d028 100644 --- a/scale-decode/src/visitor/types/composite.rs +++ b/scale-decode/src/visitor/types/composite.rs @@ -15,38 +15,36 @@ use crate::{ visitor::{DecodeError, IgnoreVisitor, Visitor}, - DecodeAsType, Field, FieldIter, + DecodeAsType, FieldIter, }; -use scale_info::{form::PortableForm, Path, PortableRegistry}; +use scale_type_resolver::{Field, TypeResolver}; /// This represents a composite type. -pub struct Composite<'scale, 'info> { +pub struct Composite<'scale, 'resolver, R: TypeResolver> { bytes: &'scale [u8], item_bytes: &'scale [u8], - path: &'info Path, - fields: smallvec::SmallVec<[Field<'info>; 16]>, + fields: smallvec::SmallVec<[Field<'resolver, R::TypeId>; 16]>, next_field_idx: usize, - types: &'info PortableRegistry, + types: &'resolver R, is_compact: bool, } -impl<'scale, 'info> Composite<'scale, 'info> { +impl<'scale, 'resolver, R: TypeResolver> Composite<'scale, 'resolver, R> { // Used in macros, but not really expected to be used elsewhere. #[doc(hidden)] pub fn new( bytes: &'scale [u8], - path: &'info Path, - fields: &mut dyn FieldIter<'info>, - types: &'info PortableRegistry, + fields: &mut dyn FieldIter<'resolver, R::TypeId>, + types: &'resolver R, is_compact: bool, - ) -> Composite<'scale, 'info> { + ) -> Composite<'scale, 'resolver, R> { let fields = smallvec::SmallVec::from_iter(fields); - Composite { bytes, path, item_bytes: bytes, fields, types, next_field_idx: 0, is_compact } + Composite { bytes, item_bytes: bytes, fields, types, next_field_idx: 0, is_compact } } /// Skip over all bytes associated with this composite type. After calling this, /// [`Self::bytes_from_undecoded()`] will represent the bytes after this composite type. pub fn skip_decoding(&mut self) -> Result<(), DecodeError> { - while let Some(res) = self.decode_item(IgnoreVisitor) { + while let Some(res) = self.decode_item(IgnoreVisitor::::new()) { res?; } Ok(()) @@ -64,47 +62,43 @@ impl<'scale, 'info> Composite<'scale, 'info> { pub fn remaining(&self) -> usize { self.fields.len() - self.next_field_idx } - /// Path to this type. - pub fn path(&self) -> &'info Path { - self.path - } /// All of the fields present in this composite type. - pub fn fields(&self) -> &[Field<'info>] { + pub fn fields(&self) -> &[Field<'resolver, R::TypeId>] { &self.fields } /// Return whether any of the fields are unnamed. pub fn has_unnamed_fields(&self) -> bool { - self.fields.iter().any(|f| f.name().is_none()) + self.fields.iter().any(|f| f.name.is_none()) } /// Convert the remaining fields in this Composite type into a [`super::Tuple`]. This allows them to /// be parsed in the same way as a tuple type, discarding name information. - pub fn as_tuple(&self) -> super::Tuple<'scale, 'info> { + pub fn as_tuple(&self) -> super::Tuple<'scale, 'resolver, R> { super::Tuple::new( self.item_bytes, - &mut self.fields.iter().copied(), + &mut self.fields.iter().cloned(), self.types, self.is_compact, ) } /// Return the name of the next field to be decoded; `None` if either the field has no name, /// or there are no fields remaining. - pub fn peek_name(&self) -> Option<&'info str> { - self.fields.get(self.next_field_idx).and_then(|f| f.name()) + pub fn peek_name(&self) -> Option<&'resolver str> { + self.fields.get(self.next_field_idx).and_then(|f| f.name) } /// Decode the next field in the composite type by providing a visitor to handle it. This is more /// efficient than iterating over the key/value pairs if you already know how you want to decode the /// values. - pub fn decode_item( + pub fn decode_item>( &mut self, visitor: V, - ) -> Option, V::Error>> { + ) -> Option, V::Error>> { let field = self.fields.get(self.next_field_idx)?; let b = &mut &*self.item_bytes; // Decode the bytes: let res = crate::visitor::decode_with_visitor_maybe_compact( b, - field.id(), + field.id, self.types, visitor, self.is_compact, @@ -124,8 +118,8 @@ impl<'scale, 'info> Composite<'scale, 'info> { } // Iterating returns a representation of each field in the composite type. -impl<'scale, 'info> Iterator for Composite<'scale, 'info> { - type Item = Result, DecodeError>; +impl<'scale, 'resolver, R: TypeResolver> Iterator for Composite<'scale, 'resolver, R> { + type Item = Result, DecodeError>; fn next(&mut self) -> Option { // Record details we need before we decode and skip over the thing: let field = *self.fields.get(self.next_field_idx)?; @@ -133,7 +127,7 @@ impl<'scale, 'info> Iterator for Composite<'scale, 'info> { let item_bytes = self.item_bytes; // Now, decode and skip over the item we're going to hand back: - if let Err(e) = self.decode_item(IgnoreVisitor)? { + if let Err(e) = self.decode_item(IgnoreVisitor::::new())? { return Some(Err(e)); }; @@ -150,39 +144,46 @@ impl<'scale, 'info> Iterator for Composite<'scale, 'info> { } /// A single field in the composite type. -#[derive(Copy, Clone)] -pub struct CompositeField<'scale, 'info> { +#[derive(Debug)] +pub struct CompositeField<'scale, 'resolver, R: TypeResolver> { bytes: &'scale [u8], - field: Field<'info>, - types: &'info PortableRegistry, + field: Field<'resolver, R::TypeId>, + types: &'resolver R, is_compact: bool, } -impl<'scale, 'info> CompositeField<'scale, 'info> { +impl<'scale, 'resolver, R: TypeResolver> Copy for CompositeField<'scale, 'resolver, R> {} +impl<'scale, 'resolver, R: TypeResolver> Clone for CompositeField<'scale, 'resolver, R> { + fn clone(&self) -> Self { + *self + } +} + +impl<'scale, 'resolver, R: TypeResolver> CompositeField<'scale, 'resolver, R> { /// The field name. - pub fn name(&self) -> Option<&'info str> { - self.field.name() + pub fn name(&self) -> Option<&'resolver str> { + self.field.name } /// The bytes associated with this field. pub fn bytes(&self) -> &'scale [u8] { self.bytes } /// The type ID associated with this field. - pub fn type_id(&self) -> u32 { - self.field.id() + pub fn type_id(&self) -> &R::TypeId { + self.field.id } /// If the field is compact encoded pub fn is_compact(&self) -> bool { self.is_compact } /// Decode this field using a visitor. - pub fn decode_with_visitor( + pub fn decode_with_visitor>( &self, visitor: V, - ) -> Result, V::Error> { + ) -> Result, V::Error> { crate::visitor::decode_with_visitor_maybe_compact( &mut &*self.bytes, - self.field.id(), + self.field.id, self.types, visitor, self.is_compact, @@ -192,18 +193,20 @@ impl<'scale, 'info> CompositeField<'scale, 'info> { pub fn decode_as_type(&self) -> Result { T::decode_as_type_maybe_compact( &mut &*self.bytes, - self.field.id(), + self.field.id, self.types, self.is_compact, ) } } -impl<'scale, 'info> crate::visitor::DecodeItemIterator<'scale, 'info> for Composite<'scale, 'info> { - fn decode_item<'a, V: Visitor>( +impl<'scale, 'resolver, R: TypeResolver> crate::visitor::DecodeItemIterator<'scale, 'resolver, R> + for Composite<'scale, 'resolver, R> +{ + fn decode_item<'a, V: Visitor>( &mut self, visitor: V, - ) -> Option, V::Error>> { + ) -> Option, V::Error>> { self.decode_item(visitor) } } diff --git a/scale-decode/src/visitor/types/sequence.rs b/scale-decode/src/visitor/types/sequence.rs index b5445c1..eef5e42 100644 --- a/scale-decode/src/visitor/types/sequence.rs +++ b/scale-decode/src/visitor/types/sequence.rs @@ -19,23 +19,23 @@ use crate::{ DecodeAsType, }; use codec::{Compact, Decode}; -use scale_info::PortableRegistry; +use scale_type_resolver::TypeResolver; /// This enables a visitor to decode items from a sequence type. -pub struct Sequence<'scale, 'info> { +pub struct Sequence<'scale, 'resolver, R: TypeResolver> { bytes: &'scale [u8], // Mostly we just delegate to our Array logic for working with sequences. // The only thing we need to do otherwise is decode the compact encoded // length from the beginning and keep track of the bytes including that. - values: Array<'scale, 'info>, + values: Array<'scale, 'resolver, R>, } -impl<'scale, 'info> Sequence<'scale, 'info> { +impl<'scale, 'resolver, R: TypeResolver> Sequence<'scale, 'resolver, R> { pub(crate) fn new( bytes: &'scale [u8], - type_id: u32, - types: &'info PortableRegistry, - ) -> Result, DecodeError> { + type_id: &'resolver R::TypeId, + types: &'resolver R, + ) -> Result, DecodeError> { // Sequences are prefixed with their length in bytes. Make a note of this, // as well as the number of bytes let item_bytes = &mut &*bytes; @@ -62,43 +62,49 @@ impl<'scale, 'info> Sequence<'scale, 'info> { self.values.remaining() } /// Decode an item from the sequence by providing a visitor to handle it. - pub fn decode_item( + pub fn decode_item>( &mut self, visitor: V, - ) -> Option, V::Error>> { + ) -> Option, V::Error>> { self.values.decode_item(visitor) } } // Iterating returns a representation of each field in the tuple type. -impl<'scale, 'info> Iterator for Sequence<'scale, 'info> { - type Item = Result, DecodeError>; +impl<'scale, 'resolver, R: TypeResolver> Iterator for Sequence<'scale, 'resolver, R> { + type Item = Result, DecodeError>; fn next(&mut self) -> Option { Some(self.values.next()?.map(|item| SequenceItem { item })) } } /// A single item in the Sequence. -#[derive(Copy, Clone)] -pub struct SequenceItem<'scale, 'info> { +pub struct SequenceItem<'scale, 'resolver, R: TypeResolver> { // Same implementation under the hood as ArrayItem: - item: ArrayItem<'scale, 'info>, + item: ArrayItem<'scale, 'resolver, R>, } -impl<'scale, 'info> SequenceItem<'scale, 'info> { +impl<'scale, 'resolver, R: TypeResolver> Copy for SequenceItem<'scale, 'resolver, R> {} +impl<'scale, 'resolver, R: TypeResolver> Clone for SequenceItem<'scale, 'resolver, R> { + fn clone(&self) -> Self { + *self + } +} + +impl<'scale, 'resolver, R: TypeResolver> SequenceItem<'scale, 'resolver, R> { /// The bytes associated with this item. pub fn bytes(&self) -> &'scale [u8] { self.item.bytes() } /// The type ID associated with this item. - pub fn type_id(&self) -> u32 { + pub fn type_id(&self) -> &R::TypeId { self.item.type_id() } /// Decode this item using a visitor. - pub fn decode_with_visitor( + pub fn decode_with_visitor>( &self, visitor: V, - ) -> Result, V::Error> { + ) -> Result, V::Error> { self.item.decode_with_visitor(visitor) } /// Decode this item into a specific type via [`DecodeAsType`]. @@ -107,11 +113,13 @@ impl<'scale, 'info> SequenceItem<'scale, 'info> { } } -impl<'scale, 'info> crate::visitor::DecodeItemIterator<'scale, 'info> for Sequence<'scale, 'info> { - fn decode_item<'a, V: Visitor>( +impl<'scale, 'resolver, R: TypeResolver> crate::visitor::DecodeItemIterator<'scale, 'resolver, R> + for Sequence<'scale, 'resolver, R> +{ + fn decode_item>( &mut self, visitor: V, - ) -> Option, V::Error>> { + ) -> Option, V::Error>> { self.decode_item(visitor) } } diff --git a/scale-decode/src/visitor/types/tuple.rs b/scale-decode/src/visitor/types/tuple.rs index 6ffcbc5..f13c815 100644 --- a/scale-decode/src/visitor/types/tuple.rs +++ b/scale-decode/src/visitor/types/tuple.rs @@ -15,34 +15,34 @@ use crate::{ visitor::{DecodeError, IgnoreVisitor, Visitor}, - DecodeAsType, Field, FieldIter, + DecodeAsType, FieldIter, }; -use scale_info::PortableRegistry; +use scale_type_resolver::{Field, TypeResolver}; /// This represents a tuple of values. -pub struct Tuple<'scale, 'info> { +pub struct Tuple<'scale, 'resolver, R: TypeResolver> { bytes: &'scale [u8], item_bytes: &'scale [u8], - fields: smallvec::SmallVec<[Field<'info>; 16]>, + fields: smallvec::SmallVec<[Field<'resolver, R::TypeId>; 16]>, next_field_idx: usize, - types: &'info PortableRegistry, + types: &'resolver R, is_compact: bool, } -impl<'scale, 'info> Tuple<'scale, 'info> { +impl<'scale, 'resolver, R: TypeResolver> Tuple<'scale, 'resolver, R> { pub(crate) fn new( bytes: &'scale [u8], - fields: &mut dyn FieldIter<'info>, - types: &'info PortableRegistry, + fields: &mut dyn FieldIter<'resolver, R::TypeId>, + types: &'resolver R, is_compact: bool, - ) -> Tuple<'scale, 'info> { + ) -> Tuple<'scale, 'resolver, R> { let fields = smallvec::SmallVec::from_iter(fields); Tuple { bytes, item_bytes: bytes, fields, types, next_field_idx: 0, is_compact } } /// Skip over all bytes associated with this tuple. After calling this, /// [`Self::bytes_from_undecoded()`] will represent the bytes after this tuple. pub fn skip_decoding(&mut self) -> Result<(), DecodeError> { - while let Some(res) = self.decode_item(IgnoreVisitor) { + while let Some(res) = self.decode_item(IgnoreVisitor::::new()) { res?; } Ok(()) @@ -61,16 +61,16 @@ impl<'scale, 'info> Tuple<'scale, 'info> { self.fields.len() } /// Decode the next item from the tuple by providing a visitor to handle it. - pub fn decode_item( + pub fn decode_item>( &mut self, visitor: V, - ) -> Option, V::Error>> { + ) -> Option, V::Error>> { let field = self.fields.get(self.next_field_idx)?; let b = &mut &*self.item_bytes; // Decode the bytes: let res = crate::visitor::decode_with_visitor_maybe_compact( b, - field.id(), + field.id, self.types, visitor, self.is_compact, @@ -90,8 +90,8 @@ impl<'scale, 'info> Tuple<'scale, 'info> { } // Iterating returns a representation of each field in the tuple type. -impl<'scale, 'info> Iterator for Tuple<'scale, 'info> { - type Item = Result, DecodeError>; +impl<'scale, 'resolver, R: TypeResolver> Iterator for Tuple<'scale, 'resolver, R> { + type Item = Result, DecodeError>; fn next(&mut self) -> Option { // Record details we need before we decode and skip over the thing: let field = *self.fields.get(self.next_field_idx)?; @@ -99,7 +99,7 @@ impl<'scale, 'info> Iterator for Tuple<'scale, 'info> { let item_bytes = self.item_bytes; // Now, decode and skip over the item we're going to hand back: - if let Err(e) = self.decode_item(IgnoreVisitor)? { + if let Err(e) = self.decode_item(IgnoreVisitor::::new())? { return Some(Err(e)); }; @@ -109,7 +109,7 @@ impl<'scale, 'info> Iterator for Tuple<'scale, 'info> { Some(Ok(TupleField { bytes: res_bytes, - type_id: field.id(), + type_id: field.id, types: self.types, is_compact: self.is_compact, })) @@ -117,21 +117,21 @@ impl<'scale, 'info> Iterator for Tuple<'scale, 'info> { } /// A single field in the tuple type. -#[derive(Copy, Clone)] -pub struct TupleField<'scale, 'info> { +#[derive(Copy, Clone, Debug)] +pub struct TupleField<'scale, 'resolver, R: TypeResolver> { bytes: &'scale [u8], - type_id: u32, - types: &'info PortableRegistry, + type_id: &'resolver R::TypeId, + types: &'resolver R, is_compact: bool, } -impl<'scale, 'info> TupleField<'scale, 'info> { +impl<'scale, 'resolver, R: TypeResolver> TupleField<'scale, 'resolver, R> { /// The bytes associated with this field. pub fn bytes(&self) -> &'scale [u8] { self.bytes } /// The type ID associated with this field. - pub fn type_id(&self) -> u32 { + pub fn type_id(&self) -> &R::TypeId { self.type_id } /// If the field is compact encoded @@ -139,10 +139,10 @@ impl<'scale, 'info> TupleField<'scale, 'info> { self.is_compact } /// Decode this field using a visitor. - pub fn decode_with_visitor( + pub fn decode_with_visitor>( &self, visitor: V, - ) -> Result, V::Error> { + ) -> Result, V::Error> { crate::visitor::decode_with_visitor(&mut &*self.bytes, self.type_id, self.types, visitor) } /// Decode this field into a specific type via [`DecodeAsType`]. @@ -156,11 +156,13 @@ impl<'scale, 'info> TupleField<'scale, 'info> { } } -impl<'scale, 'info> crate::visitor::DecodeItemIterator<'scale, 'info> for Tuple<'scale, 'info> { - fn decode_item<'a, V: Visitor>( +impl<'scale, 'resolver, R: TypeResolver> crate::visitor::DecodeItemIterator<'scale, 'resolver, R> + for Tuple<'scale, 'resolver, R> +{ + fn decode_item<'a, V: Visitor>( &mut self, visitor: V, - ) -> Option, V::Error>> { + ) -> Option, V::Error>> { self.decode_item(visitor) } } diff --git a/scale-decode/src/visitor/types/variant.rs b/scale-decode/src/visitor/types/variant.rs index 4043536..2844398 100644 --- a/scale-decode/src/visitor/types/variant.rs +++ b/scale-decode/src/visitor/types/variant.rs @@ -14,43 +14,41 @@ // limitations under the License. use crate::visitor::{Composite, DecodeError}; -use crate::Field; -use scale_info::form::PortableForm; -use scale_info::{Path, PortableRegistry, TypeDefVariant}; +use scale_type_resolver::{FieldIter, TypeResolver, VariantIter}; /// A representation of the a variant type. -pub struct Variant<'scale, 'info> { +pub struct Variant<'scale, 'resolver, R: TypeResolver> { bytes: &'scale [u8], - variant: &'info scale_info::Variant, - fields: Composite<'scale, 'info>, + variant_name: &'resolver str, + variant_index: u8, + fields: Composite<'scale, 'resolver, R>, } -impl<'scale, 'info> Variant<'scale, 'info> { - pub(crate) fn new( +impl<'scale, 'resolver, R: TypeResolver> Variant<'scale, 'resolver, R> { + pub(crate) fn new< + Fields: FieldIter<'resolver, R::TypeId> + 'resolver, + Variants: VariantIter<'resolver, Fields>, + >( bytes: &'scale [u8], - path: &'info Path, - ty: &'info TypeDefVariant, - types: &'info PortableRegistry, - ) -> Result, DecodeError> { + mut variants: Variants, + types: &'resolver R, + ) -> Result, DecodeError> { let index = *bytes.first().ok_or(DecodeError::NotEnoughInput)?; let item_bytes = &bytes[1..]; // Does a variant exist with the index we're looking for? - let variant = ty - .variants - .iter() + let mut variant = variants .find(|v| v.index == index) - .ok_or_else(|| DecodeError::VariantNotFound(index, ty.clone()))?; + .ok_or_else(|| DecodeError::VariantNotFound(index))?; // Allow decoding of the fields: - let mut fields_iter = variant.fields.iter().map(|f| Field::new(f.ty.id, f.name.as_deref())); - let fields = Composite::new(item_bytes, path, &mut fields_iter, types, false); + let fields = Composite::new(item_bytes, &mut variant.fields, types, false); - Ok(Variant { bytes, variant, fields }) + Ok(Variant { bytes, variant_index: index, variant_name: variant.name, fields }) } } -impl<'scale, 'info> Variant<'scale, 'info> { +impl<'scale, 'resolver, R: TypeResolver> Variant<'scale, 'resolver, R> { /// Skip over all bytes associated with this variant. After calling this, /// [`Self::bytes_from_undecoded()`] will represent the bytes after this variant. pub fn skip_decoding(&mut self) -> Result<(), DecodeError> { @@ -65,20 +63,16 @@ impl<'scale, 'info> Variant<'scale, 'info> { pub fn bytes_from_undecoded(&self) -> &'scale [u8] { self.fields.bytes_from_undecoded() } - /// Path to this type. - pub fn path(&self) -> &'info Path { - self.fields.path() - } /// The name of the variant. - pub fn name(&self) -> &'info str { - &self.variant.name + pub fn name(&self) -> &'resolver str { + self.variant_name } /// The index of the variant. pub fn index(&self) -> u8 { - self.variant.index + self.variant_index } /// Access the variant fields. - pub fn fields(&mut self) -> &mut Composite<'scale, 'info> { + pub fn fields(&mut self) -> &mut Composite<'scale, 'resolver, R> { &mut self.fields } }