scale-decode-derive
Derive macro for scale-decode
0.16.2
5.9M downloads/mo
#4166 most downloaded on crates.io
paritytech/scale-decode
What this package is like to depend on
Last release 9 months ago
21 Nov 2025
Release timing varies
gaps range from 2 weeks to 12 months
Nearly every release is documented
notes for 16 of 16 stable releases
1 version withdrawn
withdrawn after publishing
3 years old
17 releases · first in 2023
2 releases in the last 12 months
see the full history below
Release timeline
17 releases · Mar 2023 to Nov 2025Releases
latest 17-
0.16.221 Nov 2025Release notes
Open source →- Implement
DecodeItemIteratoron&mut Ts as well, so that we can use it more easily from visitors.
- Implement
-
0.16.119 Nov 2025Release notes
Open source →-
Expose paths in sequences and variants too
-
Address clippy and doc errors
-
Prep to release 0.16.1
-
-
0.16.015 Nov 2024Release notes
Open source →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.
Release notes
Open source →This release updates scale-bits to 0.7.0 which is exposed in the public API of scale-decode.
-
0.15.008 Nov 2024Release notes
Open source →0.15.0 - 2024-11-08
This release makes scale-decode entirely
no_stdwhich is now usingcore::error::Errorinstead ofstd::error::Erroras it was using before behind
thestd feature. Because of that thestd featureis now removed and the MSRV is bumped to 1.81.0.Release notes
Open source →This release makes scale-decode entirely
no_stdwhich is now usingcore::error::Errorinstead ofstd::error::Erroras it was using before behind thestd feature. Because of that thestd featureis now removed and the MSRV is bumped to 1.81.0.Changed
- chore(deps): use core::error::Error and make no_std (#67)
-
0.14.021 Oct 2024 -
0.13.221 Oct 2024 withdrawnRelease notes
Open source →0.13.2 - 2024-10-21
Changed
- chore(deps): bump syn from 1.0 to 2.0 (#60)
- chore(deps): bump primitives types from 0.12.0 to 0.13.1 (#61)
- chore(deps): chore(deps): bump derive_more from 0.99 to 1.0.0 (#62)
Full Changelog: v0.13.1...v0.13.2
Release notes
Open source →Yanked because
primitives-typesis re-exported from this crate and thus is a breaking change. -
0.13.107 Jun 2024Release notes
Open source →Useful visitor errors can be hidden in some cases when a
skip_decodingerror is also emitted. This patch release fixes that. -
0.13.015 May 2024Release notes
Open source →0.13.0 - 2023-05-15
This minor release avoids a couple of panics in the case of invalid bytes being interpreted as BitVecs or strings.
A small API change was made to accommodate this, such that the
Str::bytes_afternow returns a result rather than just the bytes.Fixed
Release notes
Open source →This minor release avoids a couple of panics in the case of invalid bytes being interpreted as BitVecs or strings.
A small API change was made to accommodate this, such that the
Str::bytes_afternow returns a result rather than just the bytes.Fixed
-
0.12.029 Apr 2024Release notes
Open source →0.12.0 - 2024-04-29
Update the
scale-type-resolverdependency to 0.2.0 (and bumpscale-bitsfor the same reason).The main changes here are:
- Type IDs are now passed by value rather than reference.
- The
Compositetype handed back in the visitor'svisit_composite()method now exposes the name and path of the composite type being decoded, if one was provided.
Release notes
Open source →Update the
scale-type-resolverdependency to 0.2.0 (and bumpscale-bitsfor the same reason).The main changes here are:
- Type IDs are now passed by value rather than reference.
- The
Compositetype handed back in the visitor'svisit_composite()method now exposes the name and path of the composite type being decoded, if one was provided.
-
0.11.116 Feb 2024Release notes
Open source →0.11.1 - 2023-02-16
scale-infowas still being pulled in viascale-type-resolver; this has now been fixed
Release notes
Open source →scale-infowas still being pulled in viascale-type-resolver; this has now been fixed
-
0.11.009 Feb 2024Release notes
Open source →0.11.0 - 2023-02-09
Up until now, this crate depended heavily on
scale_infoto provide the type information that we used to drive our decoding of types. This release removes the explicit dependency onscale-info, and instead depends onscale-type-resolver, which offers a genericTypeResolvertrait whose implementations are able to provide the information needed to decode types (see this PR for more details). So now, the traits and types inscale-decodehave been made generic over whichTypeResolveris used to help decode things.scale-info::PortableRegistryis one such implementation ofTypeResolver, and so can continue to be used in a similar way to before.The main breaking changes are:
Visitor trait
The
scale_decode::Visitortrait now has an additional associated type,TypeResolver.The simplest change to recover the previous behaviour is to just continue to use
scale_info::PortableRegistryfor this task, as was the case implicitly before:struct MyVisitor; impl Visitor for MyVisitor { // ... type TypeResolver = scale_info::PortableRegistry; // ... }
A better change is to make your
Visitorimpls generic over what is used to resolve types unless you need a specific resolver:struct MyVisitor<R>(PhantomData<R>); impl <R> MyVisitor<R> { pub fn new() -> Self { Self(PhantomData) } } impl <R: TypeResolver> Visitor for MyVisitor<R> { // ... type TypeResolver = R; // ... }
IntoVisitor trait
scale_decode::IntoVisitoris implemented on all types that have an associatedVisitorthat we can use to decode it. It used to look like this:pub trait IntoVisitor { type Visitor: for<'scale, 'resolver> visitor::Visitor< Value<'scale, 'resolver> = Self, Error = Error, >; fn into_visitor() -> Self::Visitor; }
Now it looks like this:
pub trait IntoVisitor { type AnyVisitor<R: TypeResolver>: for<'scale, 'resolver> visitor::Visitor< Value<'scale, 'resolver> = Self, Error = Error, TypeResolver = R, >; fn into_visitor<R: TypeResolver>() -> Self::AnyVisitor<R>; }
What this means is that if you want to implement
IntoVisitorfor some type, then yourVisitormust be able to accept any validTypeResolver. This allowsDecodeAsTypeto also be generic over whichTypeResolveris provided.DecodeAsType
This trait previously was specific to
scale_info::PortableRegistryand looked something like this:pub trait DecodeAsType: Sized + IntoVisitor { fn decode_as_type<R: TypeResolver>( input: &mut &[u8], type_id: u32, types: &scale_info::PortableRegistry, ) -> Result<Self, Error> { // ... }
Now, it is generic over which type resolver to use (and as a side effect, requires a reference to the
type_idnow, because it may not beCopyany more):pub trait DecodeAsType: Sized + IntoVisitor { fn decode_as_type<R: TypeResolver>( input: &mut &[u8], type_id: &R::TypeId, types: &R, ) -> Result<Self, Error> { // ... }
This is automatically implemented for all types which implement
IntoVisitor, as before.Composite and Variant paths
Mostly, the changes just exist to make things generic over the
TypeResolver. One consequence of this is that Composite and Variant types no longer know their path, because currentlyTypeResolverdoesn't provide that information (since it's not necessary to the actual encoding/decoding of types). If there is demand for this, we can consider allowingTypeResolverimpls to optionally provide these extra details.Release notes
Open source →Up until now, this crate depended heavily on
scale_infoto provide the type information that we used to drive our decoding of types. This release removes the explicit dependency onscale-info, and instead depends onscale-type-resolver, which offers a genericTypeResolvertrait whose implementations are able to provide the information needed to decode types (see this PR for more details). So now, the traits and types inscale-decodehave been made generic over whichTypeResolveris used to help decode things.scale-info::PortableRegistryis one such implementation ofTypeResolver, and so can continue to be used in a similar way to before.The main breaking changes are:
Visitor trait
The
scale_decode::Visitortrait now has an additional associated type,TypeResolver.The simplest change to recover the previous behaviour is to just continue to use
scale_info::PortableRegistryfor this task, as was the case implicitly before:struct MyVisitor; impl Visitor for MyVisitor { // ... type TypeResolver = scale_info::PortableRegistry; // ... }A better change is to make your
Visitorimpls generic over what is used to resolve types unless you need a specific resolver:struct MyVisitor<R>(PhantomData<R>); impl <R> MyVisitor<R> { pub fn new() -> Self { Self(PhantomData) } } impl <R: TypeResolver> Visitor for MyVisitor<R> { // ... type TypeResolver = R; // ... }IntoVisitor trait
scale_decode::IntoVisitoris implemented on all types that have an associatedVisitorthat we can use to decode it. It used to look like this:pub trait IntoVisitor { type Visitor: for<'scale, 'resolver> visitor::Visitor< Value<'scale, 'resolver> = Self, Error = Error, >; fn into_visitor() -> Self::Visitor; }Now it looks like this:
pub trait IntoVisitor { type AnyVisitor<R: TypeResolver>: for<'scale, 'resolver> visitor::Visitor< Value<'scale, 'resolver> = Self, Error = Error, TypeResolver = R, >; fn into_visitor<R: TypeResolver>() -> Self::AnyVisitor<R>; }What this means is that if you want to implement
IntoVisitorfor some type, then yourVisitormust be able to accept any validTypeResolver. This allowsDecodeAsTypeto also be generic over whichTypeResolveris provided.DecodeAsType
This trait previously was specific to
scale_info::PortableRegistryand looked something like this:pub trait DecodeAsType: Sized + IntoVisitor { fn decode_as_type<R: TypeResolver>( input: &mut &[u8], type_id: u32, types: &scale_info::PortableRegistry, ) -> Result<Self, Error> { // ... }Now, it is generic over which type resolver to use (and as a side effect, requires a reference to the
type_idnow, because it may not beCopyany more):pub trait DecodeAsType: Sized + IntoVisitor { fn decode_as_type<R: TypeResolver>( input: &mut &[u8], type_id: &R::TypeId, types: &R, ) -> Result<Self, Error> { // ... }This is automatically implemented for all types which implement
IntoVisitor, as before.Composite and Variant paths
Mostly, the changes just exist to make things generic over the
TypeResolver. One consequence of this is that Composite and Variant types no longer know their path, because currentlyTypeResolverdoesn't provide that information (since it's not necessary to the actual encoding/decoding of types). If there is demand for this, we can consider allowingTypeResolverimpls to optionally provide these extra details. -
0.10.010 Nov 2023Release notes
Open source →0.10.0 - 2023-11-10
This release changes
IntoVisitorto require that the correspondingVisitorimplementsscale_decode::Error, rather than allowing the error to be anything that can be converted into ascale_decode::Error. This has the following advantages:- It makes
DecodeAsTypea proper super-trait ofIntoVisitor, meaning it can be used anywhereIntoVisitoris. Previously, usingDecodeAsTypein some places also required that you add a bound likeB: IntoVisitor, <B::Visitor as Visitor>::Error: Into<scale_decode::Error, ie theErrortype needed to explicitly be declared as convertible in the way thatDecodeAsTyperequires. - It simplifies the code.
- It makes it a bit easier to understand how to correctly make a type implement
DecodeAsType.
The main drawback is that if your
Visitorimplementation doesn't haveError = scale_decode::Error, then it can no longer be used withIntoVisitor. To work around this, a new adapter type,scale_decode::visitor::VisitorWithCrateError(your_visitor)has been added; any visitor wrapped in this type whose error implementsInto<scale_decode::Error>will now implementVisitorwithError = scale_decode::Error.Release notes
Open source →This release changes
IntoVisitorto require that the correspondingVisitorimplementsscale_decode::Error, rather than allowing the error to be anything that can be converted into ascale_decode::Error. This has the following advantages:- It makes
DecodeAsTypea proper super-trait ofIntoVisitor, meaning it can be used anywhereIntoVisitoris. Previously, usingDecodeAsTypein some places also required that you add a bound likeB: IntoVisitor, <B::Visitor as Visitor>::Error: Into<scale_decode::Error, ie theErrortype needed to explicitly be declared as convertible in the way thatDecodeAsTyperequires. - It simplifies the code.
- It makes it a bit easier to understand how to correctly make a type implement
DecodeAsType.
The main drawback is that if your
Visitorimplementation doesn't haveError = scale_decode::Error, then it can no longer be used withIntoVisitor. To work around this, a new adapter type,scale_decode::visitor::VisitorWithCrateError(your_visitor)has been added; any visitor wrapped in this type whose error implementsInto<scale_decode::Error>will now implementVisitorwithError = scale_decode::Error. - It makes
-
0.9.002 Aug 2023Release notes
Open source →- Change how compact encoding is handled:
visit_compact_*functions are removed from theVisitortrait, and compact encoding is now handled recursively and should now work in more cases (such as nested structs with compact encoded values inside) (#32). - Improve custom error handling: custom errors now require
Debug + Displayonno_stdorErroronstd.Error::custom()now accepts anything implementing these traits rather than depending onInto<Error>(#31).
- Change how compact encoding is handled:
-
0.8.012 Jul 2023 -
0.7.031 May 2023Release notes
Open source →- Change
DecodeAsFieldsagain; remove the generic iterator parameter and use&mut dyn FieldIterinstead. This Simplifies the call signatures in a bunch of places and is consistent with howscale-encodeworks. - Use
smallvecinstead of our own stack allocated vec.
- Change
-
0.6.026 May 2023Release notes
Open source →- Change
DecodeAsFieldsto accept an iterator of fields to decode into. This makes it more flexible in what it is able to decode. This bleeds into various other types, which inherit a generic parameter to represent this iterator that is used to drive decoding.
- Change
-
0.5.013 Mar 2023Release notes
Open source →This release shifts
scale-decodeto being a mirror of a newscale-encodecrate, and:- Adds a new
IntoVisitortrait that types can implement if there is aVisitorwhich can be used to decode into them. - Adds a new
DecodeAsTypetrait to mirror theEncodeAsTypetrait there; any type that implementsIntoVisitorautomatically implementsDecodeAsType. - Adds a new
DecodeAsFieldstrait to mirrorEncodeAsFields, implemented for tuple and struct types. - Moves the
Visitortrait into a sub module and re-works the interface to allow zero copy decoding, allow more concise implementations of it, and provide a fallback escape hatch to allow for more arbitraryDecodeAsTypeimplementations from it. - Implements
DecodeAsType(viaVisitorandIntoVisitorimpls) andDecodeAsFieldson common types. - Adds a
DecodeAsTypederive macro to auto-generate impls on custom struct and enum types.
Any
Visitorimpls will need to be updated to use the refinedVisitortrait; this should be fairly mechanical (check out the examples and follow the compiler guidance to do this). Otherwise, the rest of the changes are additive and just make it easier to implement this trait and obtain aDecodeAsTypeimplementation, if desired.Changed
- Add DecodeAsType backed by Visitor impls for standard types. (#11)
- Adds a new