frame_decode/utils/
decodable_values.rs

1// Copyright (C) 2022-2025 Parity Technologies (UK) Ltd. (admin@parity.io)
2// This file is a part of the frame-decode crate.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//         http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use alloc::format;
17use alloc::vec::Vec;
18use scale_decode::DecodeAsType;
19use scale_type_resolver::TypeResolver;
20
21/// This can be implemented for any type that can be decoded into in multiple steps via
22/// [`scale_decode::DecodeAsType`]. The common use case is to decode some sets of bytes into a
23/// tuple of multiple types, step by step. As well as tuples up to size 12, Implementations also exist
24/// and arrays.
25pub trait IntoDecodableValues: Sized {
26    /// The decoder we'll use to iteratively decode bytes.
27    type Values: DecodableValues<Target = Self>;
28
29    /// Construct a type that is ready to decode values
30    /// and return the target type.
31    fn into_decodable_values() -> Self::Values;
32
33    /// The exact number of values that should be provided to
34    /// [`DecodableValues::decode_next_value()`] before
35    /// [`DecodableValues::decoded_target()`] can be called. If this
36    /// returns `None` then it indicates that any number of values
37    /// can be decoded into `Self`.
38    fn num_decodable_values() -> Option<usize>;
39}
40
41/// Implementors of this trait are capable of decoding multiple values from bytes into an output type
42/// such as a tuple or fixed size array.
43pub trait DecodableValues {
44    /// The target that we will return after decoding multiple values.
45    type Target;
46
47    /// Decode the next value. This should be called exactly as
48    /// many times as [`IntoDecodableValues::num_decodable_values`], after
49    /// which [`DecodableValues::decoded_target()`] can be called to
50    /// return the decoded target value.
51    ///
52    /// # Panics
53    ///
54    /// This method may panic if it is called more times
55    /// than [`IntoDecodableValues::num_decodable_values`].
56    fn decode_next_value<Resolver>(
57        &mut self,
58        input: &mut &[u8],
59        type_id: Resolver::TypeId,
60        types: &Resolver,
61    ) -> Result<(), scale_decode::Error>
62    where
63        Resolver: TypeResolver;
64
65    /// Return the decoded target.
66    ///
67    /// # Panics
68    ///
69    /// This method may panic if [`DecodableValues::decode_next_value`] has
70    /// not been called enough times.
71    fn decoded_target(self) -> Self::Target;
72}
73
74// Vecs
75impl<T: DecodeAsType> IntoDecodableValues for Vec<T> {
76    type Values = Self;
77    fn into_decodable_values() -> Self::Values {
78        Vec::new()
79    }
80    fn num_decodable_values() -> Option<usize> {
81        None
82    }
83}
84
85impl<T: DecodeAsType> DecodableValues for Vec<T> {
86    type Target = Self;
87
88    fn decode_next_value<Resolver>(
89        &mut self,
90        input: &mut &[u8],
91        type_id: Resolver::TypeId,
92        types: &Resolver,
93    ) -> Result<(), scale_decode::Error>
94    where
95        Resolver: TypeResolver,
96    {
97        let item = T::decode_as_type(input, type_id, types)?;
98        self.push(item);
99        Ok(())
100    }
101
102    fn decoded_target(self) -> Self::Target {
103        self
104    }
105}
106
107// Arrays
108impl<const N: usize, T: DecodeAsType> IntoDecodableValues for [T; N] {
109    type Values = DecodeArrayAsTypes<N, T>;
110    fn into_decodable_values() -> Self::Values {
111        DecodeArrayAsTypes {
112            items: [const { None }; N],
113            next_idx: 0,
114        }
115    }
116    fn num_decodable_values() -> Option<usize> {
117        Some(N)
118    }
119}
120
121pub struct DecodeArrayAsTypes<const N: usize, T> {
122    items: [Option<T>; N],
123    next_idx: usize,
124}
125
126impl<const N: usize, T: DecodeAsType> DecodableValues for DecodeArrayAsTypes<N, T> {
127    type Target = [T; N];
128
129    fn decode_next_value<Resolver>(
130        &mut self,
131        input: &mut &[u8],
132        type_id: Resolver::TypeId,
133        types: &Resolver,
134    ) -> Result<(), scale_decode::Error>
135    where
136        Resolver: TypeResolver,
137    {
138        if self.next_idx >= N {
139            let e = format!(
140                "decode_next_value called too many times (expected {N} calls) to decode [{}; N]",
141                core::any::type_name::<T>()
142            );
143            return Err(scale_decode::Error::custom_string(e));
144        }
145
146        let item = T::decode_as_type(input, type_id, types)?;
147
148        self.items[self.next_idx] = Some(item);
149        self.next_idx += 1;
150        Ok(())
151    }
152    fn decoded_target(self) -> Self::Target {
153        if self.next_idx != N {
154            panic!(
155                "decode_next_value was not called enough times (expected {N} calls, got {} calls) to decode [{}; N]",
156                self.next_idx,
157                core::any::type_name::<T>()
158            )
159        }
160
161        // This could be done slightly more efficiently with unsafe and MaybeUninit but not worth it.
162        let mut items = self.items;
163        core::array::from_fn(|idx| {
164            items[idx]
165                .take()
166                .expect("Item should be present in DecodeArrayAsType array")
167        })
168    }
169}
170
171// Empty Tuples
172impl IntoDecodableValues for () {
173    type Values = ();
174    fn into_decodable_values() -> Self::Values {}
175    fn num_decodable_values() -> Option<usize> {
176        Some(0)
177    }
178}
179
180impl DecodableValues for () {
181    type Target = ();
182
183    fn decode_next_value<Resolver>(
184        &mut self,
185        _input: &mut &[u8],
186        _type_id: Resolver::TypeId,
187        _types: &Resolver,
188    ) -> Result<(), scale_decode::Error>
189    where
190        Resolver: TypeResolver,
191    {
192        Err(scale_decode::Error::custom_str(
193            "decode_next_value cannot be called on an empty tuple",
194        ))
195    }
196
197    fn decoded_target(self) -> Self::Target {}
198}
199
200// Non-empty tuples
201macro_rules! impl_tuple_decodable {
202    ($($ty:ident $number:tt),*) => {
203        const _: () = {
204            const TUPLE_LEN: usize = 0 $(+ $number - $number + 1)*;
205
206            impl <$($ty: scale_decode::DecodeAsType),*> IntoDecodableValues for ($($ty,)*) {
207                type Values = TupleIter<$($ty),*>;
208                fn into_decodable_values() -> Self::Values {
209                    TupleIter {
210                        idx: 0,
211                        items: ($(Option::<$ty>::None,)*),
212                    }
213                }
214                fn num_decodable_values() -> Option<usize> {
215                    Some(TUPLE_LEN)
216                }
217            }
218
219            pub struct TupleIter<$($ty),*> {
220                idx: usize,
221                items: ($(Option<$ty>,)*)
222            }
223
224            impl <$($ty: scale_decode::DecodeAsType),*> DecodableValues for TupleIter<$($ty),*> {
225                type Target = ($($ty,)*);
226
227                fn decode_next_value<Resolver>(
228                    &mut self,
229                    input: &mut &[u8],
230                    type_id: Resolver::TypeId,
231                    types: &Resolver,
232                ) -> Result<(), scale_decode::Error>
233                where
234                    Resolver: TypeResolver,
235                {
236                    $(
237                        if self.idx == $number {
238                            let item = $ty::decode_as_type(input, type_id, types)?;
239                            self.items.$number = Some(item);
240                            self.idx += 1;
241                            return Ok(());
242                        }
243                    )*
244                    Err(scale_decode::Error::custom_str("decode_next_value called but no more tuple entries to decode"))
245                }
246                fn decoded_target(self) -> Self::Target {
247                    if self.idx != TUPLE_LEN {
248                        panic!(
249                            "decode_next_value not called enough times (expected {TUPLE_LEN} calls, got {} calls) to decode {}",
250                            self.idx,
251                            core::any::type_name::<Self::Target>()
252                        )
253                    }
254
255                    (
256                        $(
257                          self.items.$number.unwrap(),
258                        )*
259                    )
260                }
261            }
262        };
263    };
264}
265
266impl_tuple_decodable!(A 0);
267impl_tuple_decodable!(A 0, B 1);
268impl_tuple_decodable!(A 0, B 1, C 2);
269impl_tuple_decodable!(A 0, B 1, C 2, D 3);
270impl_tuple_decodable!(A 0, B 1, C 2, D 3, E 4);
271impl_tuple_decodable!(A 0, B 1, C 2, D 3, E 4, F 5);
272impl_tuple_decodable!(A 0, B 1, C 2, D 3, E 4, F 5, G 6);
273impl_tuple_decodable!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7);
274impl_tuple_decodable!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8);
275impl_tuple_decodable!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9);
276impl_tuple_decodable!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9, K 10);
277impl_tuple_decodable!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9, K 10, L 11);
278
279#[cfg(test)]
280mod test {
281    use super::*;
282    use parity_scale_codec::Encode;
283    use scale_info_legacy::LookupName;
284
285    fn ln(ty: &str) -> LookupName {
286        LookupName::parse(ty).unwrap()
287    }
288
289    #[test]
290    fn test_decode_empty_tuple() {
291        // We just need some basic types to test with.
292        let types = crate::legacy_types::polkadot::relay_chain();
293        let types = types.for_spec_version(0);
294
295        let n = <()>::num_decodable_values();
296        assert_eq!(n, Some(0));
297
298        // We could swap this with `()` but in theory we could change what was returned from
299        // `into_decodable_values` and want to check that this would continue working.
300        #[allow(clippy::let_unit_value)]
301        let mut decodable = <()>::into_decodable_values();
302
303        // Will error out immediately (the trait allows a panic here but our impls error)
304        decodable
305            .decode_next_value(&mut &*true.encode(), ln("bool"), &types)
306            .unwrap_err();
307
308        // This basically checks that the type of `.decoded_target()` is `()`:
309        let () = decodable.decoded_target();
310    }
311
312    #[test]
313    fn test_tuple_decodable_values() {
314        // We just need some basic types to test with.
315        let types = crate::legacy_types::polkadot::relay_chain();
316        let types = types.for_spec_version(0);
317
318        let n = <(bool, String, u64)>::num_decodable_values();
319        assert_eq!(n, Some(3));
320
321        let mut decodable = <(bool, String, u64)>::into_decodable_values();
322
323        decodable
324            .decode_next_value(&mut &*true.encode(), ln("bool"), &types)
325            .unwrap();
326        decodable
327            .decode_next_value(&mut &*"hello".encode(), ln("String"), &types)
328            .unwrap();
329        decodable
330            .decode_next_value(&mut &*123u8.encode(), ln("u8"), &types)
331            .unwrap();
332
333        // Will error out (the trait allows a panic here but our impls error)
334        decodable
335            .decode_next_value(&mut &*true.encode(), ln("bool"), &types)
336            .unwrap_err();
337
338        assert_eq!(
339            decodable.decoded_target(),
340            (true, String::from("hello"), 123u64)
341        );
342    }
343
344    #[test]
345    fn test_decode_empty_array() {
346        // We just need some basic types to test with.
347        let types = crate::legacy_types::polkadot::relay_chain();
348        let types = types.for_spec_version(0);
349
350        let n = <[u64; 0]>::num_decodable_values();
351        assert_eq!(n, Some(0));
352
353        let mut decodable = <[u64; 0]>::into_decodable_values();
354
355        // Will error out (the trait allows a panic here but our impls error)
356        decodable
357            .decode_next_value(&mut &*1u32.encode(), ln("u32"), &types)
358            .unwrap_err();
359
360        assert_eq!(decodable.decoded_target(), [] as [u64; 0]);
361    }
362
363    #[test]
364    fn test_decodable_array() {
365        // We just need some basic types to test with.
366        let types = crate::legacy_types::polkadot::relay_chain();
367        let types = types.for_spec_version(0);
368
369        let n = <[u64; 3]>::num_decodable_values();
370        assert_eq!(n, Some(3));
371
372        let mut decodable = <[u64; 3]>::into_decodable_values();
373
374        decodable
375            .decode_next_value(&mut &*1u8.encode(), ln("u8"), &types)
376            .unwrap();
377        decodable
378            .decode_next_value(&mut &*2u16.encode(), ln("u16"), &types)
379            .unwrap();
380        decodable
381            .decode_next_value(&mut &*3u32.encode(), ln("u32"), &types)
382            .unwrap();
383
384        // Will error out (the trait allows a panic here but our impls error)
385        decodable
386            .decode_next_value(&mut &*4u32.encode(), ln("u32"), &types)
387            .unwrap_err();
388
389        assert_eq!(decodable.decoded_target(), [1u64, 2u64, 3u64]);
390    }
391}