frame_decode/utils/
encodable_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::vec::Vec;
17use scale_type_resolver::TypeResolver;
18
19/// This can be implemented for anything that can be encoded in multiple steps into a set of values
20/// via [`scale_encode::EncodeAsType`]. The common use case is to encode a tuple of multiple types,
21/// step by step, into bytes. As well as tuples up to size 12, Implementations also exist for Vecs
22/// and arrays.
23pub trait IntoEncodableValues {
24    /// An implementation of [`EncodableValues`] that can be used to iterate through the values.
25    type Values<'this>: EncodableValues
26    where
27        Self: 'this;
28    /// Return an implementation of [`EncodableValues`] for this type.
29    // Dev note: for naming consistency with IntoDecodableValues we call this method
30    // into_encodable_values, but it doesn't need to take ownership of self, which
31    // clippy doesn't like, hence the allow.
32    #[allow(clippy::wrong_self_convention)]
33    fn into_encodable_values(&self) -> Self::Values<'_>;
34    /// The number of values that can be encoded from this type.
35    fn num_encodable_values(&self) -> usize;
36}
37
38/// Since [`scale_encode::EncodeAsType`] is not dyn safe, this trait is used to iterate through and
39/// encode a set of values.
40pub trait EncodableValues {
41    /// Encode the next value, if there is one, into the provided output buffer. This method
42    /// must not be called more times than [`IntoEncodableValues::num_encodable_values`].
43    ///
44    /// # Panics
45    ///
46    /// This method may panic if we call it more than [`IntoEncodableValues::num_encodable_values`]
47    /// times (ie we try to encode more values than actually exist).
48    fn encode_next_value_to<Resolver>(
49        &mut self,
50        type_id: Resolver::TypeId,
51        types: &Resolver,
52        out: &mut Vec<u8>,
53    ) -> Result<(), scale_encode::Error>
54    where
55        Resolver: TypeResolver;
56
57    /// Encode the next value, if there is one, and return the encoded bytes. This method
58    /// must not be called more times than [`IntoEncodableValues::num_encodable_values`].
59    ///
60    /// # Panics
61    ///
62    /// This method may panic if we call it more than [`IntoEncodableValues::num_encodable_values`]
63    /// times (ie we try to encode more values than actually exist).
64    fn encode_next_value<Resolver>(
65        &mut self,
66        type_id: Resolver::TypeId,
67        types: &Resolver,
68    ) -> Result<Vec<u8>, scale_encode::Error>
69    where
70        Resolver: TypeResolver,
71    {
72        let mut out = Vec::new();
73        self.encode_next_value_to(type_id, types, &mut out)
74            .map(|_| out)
75    }
76}
77
78// References are ok
79impl<'a, T: IntoEncodableValues> IntoEncodableValues for &'a T {
80    type Values<'this>
81        = T::Values<'this>
82    where
83        'a: 'this;
84
85    fn into_encodable_values(&self) -> Self::Values<'_> {
86        (*self).into_encodable_values()
87    }
88    fn num_encodable_values(&self) -> usize {
89        (*self).num_encodable_values()
90    }
91}
92
93// Vecs
94impl<K: scale_encode::EncodeAsType> IntoEncodableValues for Vec<K> {
95    type Values<'this>
96        = core::slice::Iter<'this, K>
97    where
98        K: 'this;
99    fn num_encodable_values(&self) -> usize {
100        self.len()
101    }
102    fn into_encodable_values(&self) -> Self::Values<'_> {
103        self.iter()
104    }
105}
106
107impl<'a, K: scale_encode::EncodeAsType> EncodableValues for core::slice::Iter<'a, K> {
108    fn encode_next_value_to<Resolver>(
109        &mut self,
110        type_id: Resolver::TypeId,
111        types: &Resolver,
112        out: &mut Vec<u8>,
113    ) -> Result<(), scale_encode::Error>
114    where
115        Resolver: TypeResolver,
116    {
117        let Some(next_key) = self.next() else {
118            return Err(scale_encode::Error::custom_str(
119                "encode_next_value_to called but no more values to encode",
120            ));
121        };
122        next_key.encode_as_type_to(type_id, types, out)
123    }
124}
125
126// Arrays (uses the same iter as above)
127impl<K: scale_encode::EncodeAsType, const N: usize> IntoEncodableValues for [K; N] {
128    type Values<'this>
129        = core::slice::Iter<'this, K>
130    where
131        K: 'this;
132    fn num_encodable_values(&self) -> usize {
133        N
134    }
135    fn into_encodable_values(&self) -> Self::Values<'_> {
136        self.iter()
137    }
138}
139
140// Empty tuples can be used as a placeholder for no values.
141impl IntoEncodableValues for () {
142    type Values<'this> = ();
143    fn num_encodable_values(&self) -> usize {
144        0
145    }
146    fn into_encodable_values(&self) -> Self::Values<'_> {}
147}
148
149impl EncodableValues for () {
150    fn encode_next_value_to<Resolver>(
151        &mut self,
152        _type_id: Resolver::TypeId,
153        _types: &Resolver,
154        _out: &mut Vec<u8>,
155    ) -> Result<(), scale_encode::Error>
156    where
157        Resolver: TypeResolver,
158    {
159        Err(scale_encode::Error::custom_str(
160            "encode_next_value_to called on an empty tuple",
161        ))
162    }
163}
164
165// Tuples of different lengths can be encoded as values too.
166macro_rules! impl_tuple_encodable {
167    ($($ty:ident $number:tt),*) => {
168        const _: () = {
169            const TUPLE_LEN: usize = 0 $(+ $number - $number + 1)*;
170            type TupleOf<$($ty),*> = ($($ty,)*);
171
172            impl <$($ty: scale_encode::EncodeAsType),*> IntoEncodableValues for TupleOf<$($ty),*> {
173                type Values<'this> = TupleIter<'this, TupleOf<$($ty),*>> where TupleOf<$($ty),*>: 'this;
174                fn num_encodable_values(&self) -> usize {
175                    TUPLE_LEN
176                }
177                fn into_encodable_values(&self) -> Self::Values<'_> {
178                    TupleIter {
179                        idx: 0,
180                        items: self,
181                    }
182                }
183            }
184
185            pub struct TupleIter<'this, TupleTy> {
186                idx: usize,
187                items: &'this TupleTy
188            }
189
190            impl <'a, $($ty: scale_encode::EncodeAsType),*> EncodableValues for TupleIter<'a, TupleOf<$($ty),*>> {
191                fn encode_next_value_to<Resolver>(&mut self, type_id: Resolver::TypeId, types: &Resolver, out: &mut Vec<u8>) -> Result<(), scale_encode::Error>
192                where
193                    Resolver: TypeResolver,
194                {
195                    $(
196                        if self.idx == $number {
197                            let item = &self.items.$number;
198                            item.encode_as_type_to(type_id, types, out)?;
199                            self.idx += 1;
200                            return Ok(());
201                        }
202                    )*
203                    Err(scale_encode::Error::custom_str("encode_next_value_to called but no more tuple entries to encode"))
204                }
205            }
206        };
207    };
208}
209
210impl_tuple_encodable!(A 0);
211impl_tuple_encodable!(A 0, B 1);
212impl_tuple_encodable!(A 0, B 1, C 2);
213impl_tuple_encodable!(A 0, B 1, C 2, D 3);
214impl_tuple_encodable!(A 0, B 1, C 2, D 3, E 4);
215impl_tuple_encodable!(A 0, B 1, C 2, D 3, E 4, F 5);
216impl_tuple_encodable!(A 0, B 1, C 2, D 3, E 4, F 5, G 6);
217impl_tuple_encodable!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7);
218impl_tuple_encodable!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8);
219impl_tuple_encodable!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9);
220impl_tuple_encodable!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9, K 10);
221impl_tuple_encodable!(A 0, B 1, C 2, D 3, E 4, F 5, G 6, H 7, I 8, J 9, K 10, L 11);
222
223#[cfg(test)]
224mod test {
225    use super::*;
226    use parity_scale_codec::Encode;
227    use scale_info_legacy::LookupName;
228
229    fn ln(ty: &str) -> LookupName {
230        LookupName::parse(ty).unwrap()
231    }
232
233    #[test]
234    fn test_tuple_encodable_values() {
235        // We just need some basic types to test with.
236        let types = crate::legacy_types::polkadot::relay_chain();
237        let types = types.for_spec_version(0);
238
239        let keys = (123u16, true, "hello");
240        assert_eq!(keys.num_encodable_values(), 3);
241        let mut encodable_values = keys.into_encodable_values();
242
243        let val = encodable_values
244            .encode_next_value(ln("u64"), &types)
245            .unwrap();
246        assert_eq!(val, 123u64.encode());
247
248        let val = encodable_values
249            .encode_next_value(ln("bool"), &types)
250            .unwrap();
251        assert_eq!(val, true.encode());
252
253        let val = encodable_values
254            .encode_next_value(ln("String"), &types)
255            .unwrap();
256        assert_eq!(val, "hello".encode());
257
258        // These _could_ panic in theory but our impls don't.
259        assert!(
260            encodable_values
261                .encode_next_value(ln("foo"), &types)
262                .is_err()
263        );
264        assert!(
265            encodable_values
266                .encode_next_value(ln("foo"), &types)
267                .is_err()
268        );
269    }
270
271    #[test]
272    fn test_vec_encodable_values() {
273        // We just need some basic types to test with.
274        let types = crate::legacy_types::polkadot::relay_chain();
275        let types = types.for_spec_version(0);
276
277        let keys = vec![123u16, 456u16, 789u16];
278        assert_eq!(keys.num_encodable_values(), 3);
279        let mut encodable_values = keys.into_encodable_values();
280
281        let val = encodable_values
282            .encode_next_value(ln("u64"), &types)
283            .unwrap();
284        assert_eq!(val, 123u64.encode());
285
286        let val = encodable_values
287            .encode_next_value(ln("u16"), &types)
288            .unwrap();
289        assert_eq!(val, 456u16.encode());
290
291        let val = encodable_values
292            .encode_next_value(ln("u32"), &types)
293            .unwrap();
294        assert_eq!(val, 789u32.encode());
295
296        // These _could_ panic in theory but our impls don't.
297        assert!(
298            encodable_values
299                .encode_next_value(ln("foo"), &types)
300                .is_err()
301        );
302        assert!(
303            encodable_values
304                .encode_next_value(ln("foo"), &types)
305                .is_err()
306        );
307    }
308
309    #[test]
310    fn test_array_encodable_values() {
311        // We just need some basic types to test with.
312        let types = crate::legacy_types::polkadot::relay_chain();
313        let types = types.for_spec_version(0);
314
315        let keys: [u16; 3] = [123, 456, 789];
316        assert_eq!(keys.num_encodable_values(), 3);
317        let mut encodable_values = keys.into_encodable_values();
318
319        let val = encodable_values
320            .encode_next_value(ln("u64"), &types)
321            .unwrap();
322        assert_eq!(val, 123u64.encode());
323
324        let val = encodable_values
325            .encode_next_value(ln("u16"), &types)
326            .unwrap();
327        assert_eq!(val, 456u16.encode());
328
329        let val = encodable_values
330            .encode_next_value(ln("u32"), &types)
331            .unwrap();
332        assert_eq!(val, 789u32.encode());
333
334        // These _could_ panic in theory but our impls don't.
335        assert!(
336            encodable_values
337                .encode_next_value(ln("foo"), &types)
338                .is_err()
339        );
340        assert!(
341            encodable_values
342                .encode_next_value(ln("foo"), &types)
343                .is_err()
344        );
345    }
346}