diff --git a/CHANGELOG.md b/CHANGELOG.md index b7e3c15..d67ee19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ The format is based on [Keep a Changelog]. [Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ +## 0.16.1 - 2025-11-19 + +- Expose path information in sequences and variants, too, where possible. + ## 0.16.0 - 2024-11-15 This release updates scale-bits to 0.7.0 which is exposed in the public API of scale-decode. diff --git a/Cargo.toml b/Cargo.toml index 8d67266..92f308d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ members = [ resolver = "2" [workspace.package] -version = "0.16.0" +version = "0.16.1" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -18,5 +18,5 @@ include = ["Cargo.toml", "src/**/*.rs", "README.md", "LICENSE"] rust-version = "1.81.0" [workspace.dependencies] -scale-decode = { version = "0.16.0", path = "scale-decode" } -scale-decode-derive = { version = "0.16.0", path = "scale-decode-derive" } +scale-decode = { version = "0.16.1", path = "scale-decode" } +scale-decode-derive = { version = "0.16.1", path = "scale-decode-derive" } diff --git a/scale-decode/src/error/context.rs b/scale-decode/src/error/context.rs index 5dbb440..aab2a58 100644 --- a/scale-decode/src/error/context.rs +++ b/scale-decode/src/error/context.rs @@ -42,7 +42,7 @@ impl Context { } /// The current path that we're trying to encode. -pub struct Path<'a>(Cow<'a, Vec>); +pub struct Path<'a>(Cow<'a, [Location]>); impl<'a> Path<'a> { /// Cheaply convert the path to an owned version. diff --git a/scale-decode/src/visitor/decode.rs b/scale-decode/src/visitor/decode.rs index 52af01a..198f9b7 100644 --- a/scale-decode/src/visitor/decode.rs +++ b/scale-decode/src/visitor/decode.rs @@ -145,7 +145,7 @@ impl<'temp, 'scale, 'resolver, V: Visitor> ResolvedTypeVisitor<'resolver> skip_decoding_and_return!(self, res, items) } - fn visit_variant(self, _path: Path, variants: Var) -> Self::Value + fn visit_variant(self, path: Path, variants: Var) -> Self::Value where Path: PathIter<'resolver>, Fields: FieldIter<'resolver, Self::TypeId>, @@ -155,13 +155,13 @@ impl<'temp, 'scale, 'resolver, V: Visitor> ResolvedTypeVisitor<'resolver> return Err(DecodeError::CannotDecodeCompactIntoType.into()); } - let mut variant = Variant::new(self.data, variants, self.types)?; + let mut variant = Variant::new(path, self.data, variants, self.types)?; let res = self.visitor.visit_variant(&mut variant, self.type_id); skip_decoding_and_return!(self, res, variant) } - fn visit_sequence(self, _path: Path, inner_type_id: Self::TypeId) -> Self::Value + fn visit_sequence(self, path: Path, inner_type_id: Self::TypeId) -> Self::Value where Path: PathIter<'resolver>, { @@ -169,7 +169,7 @@ impl<'temp, 'scale, 'resolver, V: Visitor> ResolvedTypeVisitor<'resolver> return Err(DecodeError::CannotDecodeCompactIntoType.into()); } - let mut items = Sequence::new(self.data, inner_type_id, self.types)?; + let mut items = Sequence::new(path, self.data, inner_type_id, self.types)?; let res = self.visitor.visit_sequence(&mut items, self.type_id); skip_decoding_and_return!(self, res, items) diff --git a/scale-decode/src/visitor/mod.rs b/scale-decode/src/visitor/mod.rs index f1bfc19..44a7866 100644 --- a/scale-decode/src/visitor/mod.rs +++ b/scale-decode/src/visitor/mod.rs @@ -42,8 +42,8 @@ pub trait Visitor: Sized { 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 - /// do some decoding at this stage, return [`DecodeAsTypeResult::Decoded(result)`]. In either case, any bytes + /// this call and return our visitor back (ie [`DecodeAsTypeResult::Skipped`]). If you choose to + /// do some decoding at this stage, return [`DecodeAsTypeResult::Decoded`]. In either case, any bytes /// that you consume from the input (by altering what it points to) will be consumed for any subsequent visiting. /// /// # Warning diff --git a/scale-decode/src/visitor/types/sequence.rs b/scale-decode/src/visitor/types/sequence.rs index b9ada17..f96aa54 100644 --- a/scale-decode/src/visitor/types/sequence.rs +++ b/scale-decode/src/visitor/types/sequence.rs @@ -28,20 +28,32 @@ pub struct Sequence<'scale, 'resolver, R: TypeResolver> { // 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, 'resolver, R>, + path: smallvec::SmallVec<[&'resolver str; 5]>, } impl<'scale, 'resolver, R: TypeResolver> Sequence<'scale, 'resolver, R> { pub(crate) fn new( + path: impl Iterator, bytes: &'scale [u8], type_id: R::TypeId, types: &'resolver R, ) -> Result, DecodeError> { + let path = smallvec::SmallVec::from_iter(path); + // 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; let len = >::decode(item_bytes)?.0 as usize; - Ok(Sequence { bytes, values: Array::new(item_bytes, type_id, len, types) }) + Ok(Sequence { path, bytes, values: Array::new(item_bytes, type_id, len, types) }) + } + /// Return the name of the sequence type, if one was given. + pub fn name(&self) -> Option<&'resolver str> { + self.path.iter().last().copied() + } + /// Return the full path to the sequence type (including the name) if one was given. + pub fn path(&self) -> impl Iterator + '_ { + self.path.iter().copied() } /// Skip over all bytes associated with this sequence. After calling this, /// [`Self::bytes_from_undecoded()`] will represent the bytes after this sequence. diff --git a/scale-decode/src/visitor/types/variant.rs b/scale-decode/src/visitor/types/variant.rs index 8c6232d..f36e205 100644 --- a/scale-decode/src/visitor/types/variant.rs +++ b/scale-decode/src/visitor/types/variant.rs @@ -22,6 +22,7 @@ pub struct Variant<'scale, 'resolver, R: TypeResolver> { variant_name: &'resolver str, variant_index: u8, fields: Composite<'scale, 'resolver, R>, + path: smallvec::SmallVec<[&'resolver str; 5]>, } impl<'scale, 'resolver, R: TypeResolver> Variant<'scale, 'resolver, R> { @@ -29,10 +30,12 @@ impl<'scale, 'resolver, R: TypeResolver> Variant<'scale, 'resolver, R> { Fields: FieldIter<'resolver, R::TypeId>, Variants: VariantIter<'resolver, Fields>, >( + path: impl Iterator, bytes: &'scale [u8], mut variants: Variants, types: &'resolver R, ) -> Result, DecodeError> { + let path = smallvec::SmallVec::from_iter(path); let index = *bytes.first().ok_or(DecodeError::NotEnoughInput)?; let item_bytes = &bytes[1..]; @@ -49,11 +52,19 @@ impl<'scale, 'resolver, R: TypeResolver> Variant<'scale, 'resolver, R> { false, ); - Ok(Variant { bytes, variant_index: index, variant_name: variant.name, fields }) + Ok(Variant { path, bytes, variant_index: index, variant_name: variant.name, fields }) } } impl<'scale, 'resolver, R: TypeResolver> Variant<'scale, 'resolver, R> { + /// Return the name of the enum type that this variant belongs to, if one was given. + pub fn enum_name(&self) -> Option<&'resolver str> { + self.path.iter().last().copied() + } + /// Return the full path to the variant type (including the enum name) if one was given. + pub fn path(&self) -> impl Iterator + '_ { + self.path.iter().copied() + } /// 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> {