Skip to main content

alloy_sol_types/abi/
token.rs

1// Copyright 2015-2020 Parity Technologies
2// Copyright 2023-2023 Alloy Contributors
3
4// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7// option. This file may not be copied, modified, or distributed
8// except according to those terms.
9
10//! Ethereum ABI tokens.
11//!
12//! See [`Token`] for more details.
13
14use crate::{
15    Result, Word,
16    abi::{Decoder, Encoder},
17};
18use alloc::vec::Vec;
19use alloy_primitives::{Bytes, FixedBytes, I256, U256, hex, utils::vec_try_with_capacity};
20use core::{fmt, mem, mem::MaybeUninit, ptr};
21
22#[allow(unknown_lints, unnameable_types)]
23mod sealed {
24    pub trait Sealed {}
25    impl Sealed for super::WordToken {}
26    impl Sealed for () {}
27    impl<T, const N: usize> Sealed for super::FixedSeqToken<T, N> {}
28    impl<T> Sealed for super::DynSeqToken<T> {}
29    impl Sealed for super::PackedSeqToken<'_> {}
30}
31use sealed::Sealed;
32
33/// Ethereum ABI tokens.
34///
35/// Tokens are an intermediate state between ABI-encoded blobs, and Rust types.
36///
37/// ABI encoding uses 5 types:
38/// - [`WordToken`]: Single EVM words (a 32-byte string)
39/// - [`FixedSeqToken`]: Sequences with a fixed length `T[M]`
40/// - [`DynSeqToken`]: Sequences with a dynamic length `T[]`
41/// - [`PackedSeqToken`]: Dynamic-length byte arrays `bytes` or `string`
42/// - Tuples `(T, U, V, ...)` (implemented for arity `0..=24`)
43///
44/// A token with a lifetime borrows its data from elsewhere. During decoding,
45/// it borrows its data from the decoder. During encoding, it borrows its data
46/// from the Rust value being encoded.
47///
48/// This trait allows us to encode and decode data with minimal copying. It may
49/// also be used to enable zero-copy decoding of data, or fast transformation of
50/// encoded blobs without full decoding.
51///
52/// This trait is sealed and cannot be implemented for types outside of this
53/// crate. It is implemented only for the types listed above.
54pub trait Token<'de>: Sealed + Sized {
55    /// True if the token represents a dynamically-sized type.
56    const DYNAMIC: bool;
57
58    /// The minimum number of words required in the containing head.
59    const MINIMUM_WORDS: usize;
60
61    /// Decode a token from a decoder.
62    fn decode_from(dec: &mut Decoder<'de, '_>) -> Result<Self>;
63
64    /// Decode tokens from a decoder into the given uninitialized buffer.
65    ///
66    /// On success, returns the initialized slice.
67    /// On error, no elements are initialized (partially initialized elements are dropped).
68    ///
69    /// The default implementation simply loops over [`decode_from`](Self::decode_from).
70    /// Implementations may override this to provide a more efficient batch decode,
71    /// e.g. a single `memcpy` for [`WordToken`].
72    ///
73    /// # Safety
74    ///
75    /// `out` must point to valid, writable memory for `out.len()` elements.
76    #[inline]
77    unsafe fn decode_many_from<'a>(
78        dec: &mut Decoder<'de, '_>,
79        out: &'a mut [MaybeUninit<Self>],
80    ) -> Result<&'a mut [Self]> {
81        try_init_each(out, || Self::decode_from(dec))
82    }
83
84    /// Calculate the number of head words.
85    fn head_words(&self) -> usize;
86
87    /// Calculate the number of tail words.
88    fn tail_words(&self) -> usize;
89
90    /// Calculate the total number of head and tail words.
91    #[inline]
92    fn total_words(&self) -> usize {
93        self.head_words() + self.tail_words()
94    }
95
96    /// Append head words to the encoder.
97    fn head_append(&self, enc: &mut Encoder);
98
99    /// Append head words for a slice of tokens to the encoder.
100    ///
101    /// The default implementation simply loops over [`head_append`](Self::head_append).
102    /// Implementations may override this to provide a more efficient batch encode,
103    /// e.g. a single `memcpy` for [`WordToken`].
104    #[inline]
105    fn head_append_many(tokens: &[Self], enc: &mut Encoder) {
106        for token in tokens {
107            token.head_append(enc);
108        }
109    }
110
111    /// Append tail words to the encoder.
112    fn tail_append(&self, enc: &mut Encoder);
113}
114
115/// A token composed of a sequence of other tokens.
116///
117/// This functions is an extension trait for [`Token`], and is only
118/// implemented by [`FixedSeqToken`], [`DynSeqToken`], [`PackedSeqToken`], and
119/// tuples of [`Token`]s (including [`WordToken`]).
120pub trait TokenSeq<'a>: Token<'a> {
121    /// True for tuples only.
122    const IS_TUPLE: bool = false;
123
124    /// ABI-encode the token sequence into the encoder.
125    fn encode_sequence(&self, enc: &mut Encoder);
126
127    /// ABI-decode the token sequence from the encoder.
128    fn decode_sequence(dec: &mut Decoder<'a, '_>) -> Result<Self>;
129}
130
131/// A single EVM word - T for any value type.
132#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
133#[repr(transparent)]
134pub struct WordToken(pub Word);
135
136impl<T> From<&T> for WordToken
137where
138    T: Clone,
139    Self: From<T>,
140{
141    #[inline]
142    fn from(value: &T) -> Self {
143        Self::from(value.clone())
144    }
145}
146
147impl<T> From<&mut T> for WordToken
148where
149    T: Clone,
150    Self: From<T>,
151{
152    #[inline]
153    fn from(value: &mut T) -> Self {
154        Self::from(value.clone())
155    }
156}
157
158impl From<Word> for WordToken {
159    #[inline]
160    fn from(value: Word) -> Self {
161        Self(value)
162    }
163}
164
165impl From<WordToken> for Word {
166    #[inline]
167    fn from(value: WordToken) -> Self {
168        value.0
169    }
170}
171
172impl From<bool> for WordToken {
173    #[inline]
174    fn from(value: bool) -> Self {
175        U256::from(value as u64).into()
176    }
177}
178
179impl From<U256> for WordToken {
180    #[inline]
181    fn from(value: U256) -> Self {
182        Self(value.into())
183    }
184}
185
186impl From<I256> for WordToken {
187    #[inline]
188    fn from(value: I256) -> Self {
189        Self(value.into())
190    }
191}
192
193impl From<WordToken> for [u8; 32] {
194    #[inline]
195    fn from(value: WordToken) -> [u8; 32] {
196        value.0.into()
197    }
198}
199
200impl From<[u8; 32]> for WordToken {
201    #[inline]
202    fn from(value: [u8; 32]) -> Self {
203        Self(value.into())
204    }
205}
206
207impl AsRef<Word> for WordToken {
208    #[inline]
209    fn as_ref(&self) -> &Word {
210        &self.0
211    }
212}
213
214impl AsRef<[u8]> for WordToken {
215    #[inline]
216    fn as_ref(&self) -> &[u8] {
217        &self.0.0
218    }
219}
220
221impl<'a> Token<'a> for WordToken {
222    const DYNAMIC: bool = false;
223    const MINIMUM_WORDS: usize = 1;
224
225    #[inline]
226    fn decode_from(dec: &mut Decoder<'a, '_>) -> Result<Self> {
227        dec.take_word().copied().map(Self)
228    }
229
230    #[inline]
231    unsafe fn decode_many_from<'b>(
232        dec: &mut Decoder<'a, '_>,
233        out: &'b mut [MaybeUninit<Self>],
234    ) -> Result<&'b mut [Self]> {
235        let len = out.len();
236        let byte_len = len * Word::len_bytes();
237        let slice = dec.take_slice(byte_len)?;
238        // SAFETY: `MaybeUninit<WordToken>` has the same layout as `WordToken` which is
239        // `#[repr(transparent)]` over `Word` (`[u8; 32]`), all with alignment 1.
240        // `slice` is exactly `len * 32` bytes, matching the output layout.
241        unsafe {
242            core::ptr::copy_nonoverlapping(slice.as_ptr(), out.as_mut_ptr().cast::<u8>(), byte_len);
243            Ok(core::slice::from_raw_parts_mut(out.as_mut_ptr().cast::<Self>(), len))
244        }
245    }
246
247    #[inline]
248    fn head_words(&self) -> usize {
249        1
250    }
251
252    #[inline]
253    fn tail_words(&self) -> usize {
254        0
255    }
256
257    #[inline]
258    fn head_append(&self, enc: &mut Encoder) {
259        enc.append_word(self.0);
260    }
261
262    #[inline]
263    fn head_append_many(tokens: &[Self], enc: &mut Encoder) {
264        // SAFETY: `WordToken` is `#[repr(transparent)]` over `Word`.
265        let words = unsafe { &*(tokens as *const [Self] as *const [Word]) };
266        enc.append_words(words);
267    }
268
269    #[inline]
270    fn tail_append(&self, _enc: &mut Encoder) {}
271}
272
273impl WordToken {
274    /// Create a new word token from a word.
275    #[inline]
276    pub const fn new(array: [u8; 32]) -> Self {
277        Self(FixedBytes(array))
278    }
279
280    /// Returns a reference to the word as a slice.
281    #[inline]
282    pub const fn as_slice(&self) -> &[u8] {
283        &self.0.0
284    }
285}
286
287/// A Fixed Sequence - `T[N]`
288#[derive(Clone, Debug, PartialEq, Eq)]
289pub struct FixedSeqToken<T, const N: usize>(pub [T; N]);
290
291impl<T, const N: usize> TryFrom<Vec<T>> for FixedSeqToken<T, N> {
292    type Error = <[T; N] as TryFrom<Vec<T>>>::Error;
293
294    #[inline]
295    fn try_from(value: Vec<T>) -> Result<Self, Self::Error> {
296        <[T; N]>::try_from(value).map(Self)
297    }
298}
299
300impl<T, const N: usize> From<[T; N]> for FixedSeqToken<T, N> {
301    #[inline]
302    fn from(value: [T; N]) -> Self {
303        Self(value)
304    }
305}
306
307impl<T, const N: usize> AsRef<[T; N]> for FixedSeqToken<T, N> {
308    #[inline]
309    fn as_ref(&self) -> &[T; N] {
310        &self.0
311    }
312}
313
314impl<'de, T: Token<'de>, const N: usize> Token<'de> for FixedSeqToken<T, N> {
315    const DYNAMIC: bool = T::DYNAMIC;
316    const MINIMUM_WORDS: usize = if Self::DYNAMIC { 1 } else { T::MINIMUM_WORDS.saturating_mul(N) };
317
318    #[inline]
319    fn decode_from(dec: &mut Decoder<'de, '_>) -> Result<Self> {
320        if Self::DYNAMIC {
321            dec.take_indirection().and_then(|mut child| Self::decode_sequence(&mut child))
322        } else {
323            Self::decode_sequence(dec)
324        }
325    }
326
327    #[inline]
328    fn head_words(&self) -> usize {
329        if Self::DYNAMIC {
330            // offset
331            1
332        } else {
333            // elements
334            self.0.iter().map(T::total_words).sum()
335        }
336    }
337
338    #[inline]
339    fn tail_words(&self) -> usize {
340        if Self::DYNAMIC {
341            // elements
342            self.0.iter().map(T::total_words).sum()
343        } else {
344            0
345        }
346    }
347
348    #[inline]
349    fn head_append(&self, enc: &mut Encoder) {
350        if Self::DYNAMIC {
351            enc.append_indirection();
352        } else {
353            T::head_append_many(&self.0, enc);
354        }
355    }
356
357    #[inline]
358    fn tail_append(&self, enc: &mut Encoder) {
359        if Self::DYNAMIC {
360            self.encode_sequence(enc);
361        }
362    }
363}
364
365impl<'de, T: Token<'de>, const N: usize> TokenSeq<'de> for FixedSeqToken<T, N> {
366    #[inline]
367    fn encode_sequence(&self, enc: &mut Encoder) {
368        encode_sequence_impl(&self.0, enc);
369    }
370
371    #[inline]
372    fn decode_sequence(dec: &mut Decoder<'de, '_>) -> Result<Self> {
373        dec.set_strict_head_words(T::MINIMUM_WORDS.checked_mul(N).ok_or(crate::Error::Overrun)?)?;
374        let mut arr = crate::impl_core::uninit_array::<T, N>();
375        // SAFETY: `arr` is valid writable memory for `N` elements.
376        // `decode_many_from` initializes all elements on success.
377        unsafe {
378            T::decode_many_from(dec, &mut arr)?;
379            Ok(Self(crate::impl_core::array_assume_init(arr)))
380        }
381    }
382}
383
384impl<T, const N: usize> FixedSeqToken<T, N> {
385    /// Take the backing array, consuming the token.
386    // https://github.com/rust-lang/rust-clippy/issues/4979
387    #[allow(clippy::missing_const_for_fn)]
388    #[inline]
389    pub fn into_array(self) -> [T; N] {
390        self.0
391    }
392
393    /// Returns a reference to the array.
394    #[inline]
395    pub const fn as_array(&self) -> &[T; N] {
396        &self.0
397    }
398
399    /// Returns a reference to the array as a slice.
400    #[inline]
401    pub const fn as_slice(&self) -> &[T] {
402        &self.0
403    }
404}
405
406/// A Dynamic Sequence - `T[]`
407#[derive(Clone, Debug, PartialEq, Eq)]
408pub struct DynSeqToken<T>(pub Vec<T>);
409
410impl<T> From<Vec<T>> for DynSeqToken<T> {
411    #[inline]
412    fn from(value: Vec<T>) -> Self {
413        Self(value)
414    }
415}
416
417impl<T> AsRef<[T]> for DynSeqToken<T> {
418    #[inline]
419    fn as_ref(&self) -> &[T] {
420        self.0.as_ref()
421    }
422}
423
424impl<'de, T: Token<'de>> Token<'de> for DynSeqToken<T> {
425    const DYNAMIC: bool = true;
426    const MINIMUM_WORDS: usize = 1;
427
428    #[inline]
429    fn decode_from(dec: &mut Decoder<'de, '_>) -> Result<Self> {
430        let mut child = dec.take_indirection()?;
431        let len = child.take_offset()?;
432        if T::MINIMUM_WORDS == 0 {
433            debug_assert_eq!(core::mem::size_of::<T>(), 0);
434            if child.is_strict() && len != 0 {
435                return Err(crate::Error::ReserMismatch);
436            }
437            // Charge a byte per element to bound work on zero-sized tokens.
438            child.reserve(len)?;
439            #[allow(clippy::uninit_vec)]
440            let tokens = {
441                let mut tokens = Vec::new();
442                // SAFETY: `MINIMUM_WORDS == 0` is only implemented for zero-sized
443                // token types. A `Vec` of a zero-sized type has `usize::MAX`
444                // capacity, so setting its length does not allocate or initialize
445                // memory.
446                unsafe { tokens.set_len(len) };
447                tokens
448            };
449            return Ok(Self(tokens));
450        }
451        // This appears to be an unclarity in the Solidity spec. The spec
452        // specifies that offsets are relative to the first word of
453        // `enc(X)`. But known-good test vectors are relative to the
454        // word AFTER the array size
455        let required_words = T::MINIMUM_WORDS.checked_mul(len).ok_or(crate::Error::Overrun)?;
456        let mut child = child.raw_child()?;
457        child.set_strict_head_words(required_words)?;
458        if required_words > child.remaining_words() {
459            return Err(crate::Error::Overrun);
460        }
461        if child.is_strict() && T::DYNAMIC {
462            let mut tokens = Vec::new();
463            for _ in 0..len {
464                let token = T::decode_from(&mut child)?;
465                if tokens.len() == tokens.capacity() {
466                    let additional = tokens.capacity().max(1).min(len - tokens.len());
467                    child.reserve_elements::<T>(additional)?;
468                    tokens.try_reserve_exact(additional)?;
469                }
470                tokens.push(token);
471            }
472            return Ok(Self(tokens));
473        }
474        child.reserve_elements::<T>(len)?;
475        let mut tokens = vec_try_with_capacity(len)?;
476        // SAFETY: `spare_capacity_mut` returns valid writable memory.
477        // `decode_many_from` initializes all `len` elements on success.
478        unsafe {
479            T::decode_many_from(&mut child, &mut tokens.spare_capacity_mut()[..len])?;
480            tokens.set_len(len);
481        }
482        Ok(Self(tokens))
483    }
484
485    #[inline]
486    fn head_words(&self) -> usize {
487        // offset
488        1
489    }
490
491    #[inline]
492    fn tail_words(&self) -> usize {
493        // length + elements
494        1 + self.0.iter().map(T::total_words).sum::<usize>()
495    }
496
497    #[inline]
498    fn head_append(&self, enc: &mut Encoder) {
499        enc.append_indirection();
500    }
501
502    #[inline]
503    fn tail_append(&self, enc: &mut Encoder) {
504        enc.append_seq_len(self.0.len());
505        self.encode_sequence(enc);
506    }
507}
508
509impl<'de, T: Token<'de>> TokenSeq<'de> for DynSeqToken<T> {
510    #[inline]
511    fn encode_sequence(&self, enc: &mut Encoder) {
512        encode_sequence_impl(&self.0, enc);
513    }
514
515    #[inline]
516    fn decode_sequence(dec: &mut Decoder<'de, '_>) -> Result<Self> {
517        dec.set_strict_head_words(Self::MINIMUM_WORDS)?;
518        Self::decode_from(dec)
519    }
520}
521
522impl<T> DynSeqToken<T> {
523    /// Returns a reference to the backing slice.
524    #[inline]
525    pub fn as_slice(&self) -> &[T] {
526        &self.0
527    }
528}
529
530/// A Packed Sequence - `bytes` or `string`
531#[derive(Clone, Copy, PartialEq, Eq)]
532pub struct PackedSeqToken<'a>(pub &'a [u8]);
533
534impl fmt::Debug for PackedSeqToken<'_> {
535    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
536        f.debug_tuple("PackedSeqToken").field(&hex::encode_prefixed(self.0)).finish()
537    }
538}
539
540impl<'a> From<&'a [u8]> for PackedSeqToken<'a> {
541    #[inline]
542    fn from(value: &'a [u8]) -> Self {
543        Self(value)
544    }
545}
546
547impl<'a> From<&'a Vec<u8>> for PackedSeqToken<'a> {
548    #[inline]
549    fn from(value: &'a Vec<u8>) -> Self {
550        Self(value.as_slice())
551    }
552}
553
554impl AsRef<[u8]> for PackedSeqToken<'_> {
555    #[inline]
556    fn as_ref(&self) -> &[u8] {
557        self.0
558    }
559}
560
561impl<'de: 'a, 'a> Token<'de> for PackedSeqToken<'a> {
562    const DYNAMIC: bool = true;
563    const MINIMUM_WORDS: usize = 1;
564
565    #[inline]
566    fn decode_from(dec: &mut Decoder<'de, '_>) -> Result<Self> {
567        let mut child = dec.take_indirection()?;
568        let len = child.take_offset()?;
569        let bytes = child.take_padded_slice(len)?;
570        child.reserve(len)?;
571        Ok(PackedSeqToken(bytes))
572    }
573
574    #[inline]
575    fn head_words(&self) -> usize {
576        // offset
577        1
578    }
579
580    #[inline]
581    fn tail_words(&self) -> usize {
582        // length + words(data)
583        1 + crate::utils::words_for(self.0)
584    }
585
586    #[inline]
587    fn head_append(&self, enc: &mut Encoder) {
588        enc.append_indirection();
589    }
590
591    #[inline]
592    fn tail_append(&self, enc: &mut Encoder) {
593        enc.append_packed_seq(self.0);
594    }
595}
596
597impl PackedSeqToken<'_> {
598    /// Instantiate a new [`Vec`] by copying the underlying slice.
599    // https://github.com/rust-lang/rust-clippy/issues/4979
600    #[allow(clippy::missing_const_for_fn)]
601    #[inline]
602    pub fn into_vec(self) -> Vec<u8> {
603        self.0.to_vec()
604    }
605
606    /// Instantiate a new [`Bytes`] by copying the underlying slice.
607    pub fn into_bytes(self) -> Bytes {
608        Bytes::copy_from_slice(self.0)
609    }
610
611    /// Returns a reference to the slice.
612    #[inline]
613    pub const fn as_slice(&self) -> &[u8] {
614        self.0
615    }
616}
617
618macro_rules! tuple_impls {
619    ($count:literal $($ty:ident),+) => {
620        impl<'de, $($ty: Token<'de>,)+> Sealed for ($($ty,)+) {}
621
622        #[allow(non_snake_case)]
623        impl<'de, $($ty: Token<'de>,)+> Token<'de> for ($($ty,)+) {
624            const DYNAMIC: bool = $( <$ty as Token>::DYNAMIC )||+;
625            const MINIMUM_WORDS: usize = if Self::DYNAMIC {
626                1
627            } else {
628                0usize $( .saturating_add(<$ty as Token>::MINIMUM_WORDS) )+
629            };
630
631            #[inline]
632            fn decode_from(dec: &mut Decoder<'de, '_>) -> Result<Self> {
633                // The first element in a dynamic tuple is an offset to the tuple's data;
634                // for a static tuples, the data begins right away
635                if Self::DYNAMIC {
636                    dec.take_indirection().and_then(|mut child| Self::decode_sequence(&mut child))
637                } else {
638                    Self::decode_sequence(dec)
639                }
640            }
641
642            #[inline]
643            fn head_words(&self) -> usize {
644                if Self::DYNAMIC {
645                    // offset
646                    1
647                } else {
648                    // elements
649                    let ($($ty,)+) = self;
650                    0 $( + $ty.total_words() )+
651                }
652            }
653
654            #[inline]
655            fn tail_words(&self) -> usize {
656                if Self::DYNAMIC {
657                    // elements
658                    let ($($ty,)+) = self;
659                    0 $( + $ty.total_words() )+
660                } else {
661                    0
662                }
663            }
664
665            #[inline]
666            fn head_append(&self, enc: &mut Encoder) {
667                if Self::DYNAMIC {
668                    enc.append_indirection();
669                } else {
670                    let ($($ty,)+) = self;
671                    $(
672                        $ty.head_append(enc);
673                    )+
674                }
675            }
676
677            #[inline]
678            fn tail_append(&self, enc: &mut Encoder) {
679                if Self::DYNAMIC {
680                    self.encode_sequence(enc);
681                }
682            }
683        }
684
685        #[allow(non_snake_case)]
686        impl<'de, $($ty: Token<'de>,)+> TokenSeq<'de> for ($($ty,)+) {
687            const IS_TUPLE: bool = true;
688
689            fn encode_sequence(&self, enc: &mut Encoder) {
690                let ($($ty,)+) = self;
691                enc.push_offset(0 $( + $ty.head_words() )+);
692
693                $(
694                    $ty.head_append(enc);
695                    enc.bump_offset($ty.tail_words());
696                )+
697
698                $(
699                    $ty.tail_append(enc);
700                )+
701
702                enc.pop_offset();
703            }
704
705            #[inline]
706            fn decode_sequence(dec: &mut Decoder<'de, '_>) -> Result<Self> {
707                let head_words = 0usize $(
708                    .checked_add(<$ty as Token>::MINIMUM_WORDS)
709                    .ok_or(crate::Error::Overrun)?
710                )+;
711                dec.set_strict_head_words(head_words)?;
712                Ok(($(
713                    match <$ty as Token>::decode_from(dec) {
714                        Ok(t) => t,
715                        Err(e) => return Err(e),
716                    },
717                )+))
718            }
719        }
720    };
721}
722
723impl<'de> Token<'de> for () {
724    const DYNAMIC: bool = false;
725    const MINIMUM_WORDS: usize = 0;
726
727    #[inline]
728    fn decode_from(_dec: &mut Decoder<'de, '_>) -> Result<Self> {
729        Ok(())
730    }
731
732    #[inline]
733    fn head_words(&self) -> usize {
734        0
735    }
736
737    #[inline]
738    fn tail_words(&self) -> usize {
739        0
740    }
741
742    #[inline]
743    fn head_append(&self, _enc: &mut Encoder) {}
744
745    #[inline]
746    fn tail_append(&self, _enc: &mut Encoder) {}
747}
748
749impl<'de> TokenSeq<'de> for () {
750    const IS_TUPLE: bool = true;
751
752    #[inline]
753    fn encode_sequence(&self, _enc: &mut Encoder) {}
754
755    #[inline]
756    fn decode_sequence(_dec: &mut Decoder<'de, '_>) -> Result<Self> {
757        Ok(())
758    }
759}
760
761all_the_tuples!(tuple_impls);
762
763/// Shared implementation for [`TokenSeq::encode_sequence`] used by both
764/// [`FixedSeqToken`] and [`DynSeqToken`].
765fn encode_sequence_impl<'de, T: Token<'de>>(tokens: &[T], enc: &mut Encoder) {
766    if T::DYNAMIC {
767        enc.push_offset(tokens.iter().map(T::head_words).sum());
768
769        for inner in tokens {
770            inner.head_append(enc);
771            enc.bump_offset(inner.tail_words());
772        }
773        for inner in tokens {
774            inner.tail_append(enc);
775        }
776
777        enc.pop_offset();
778    } else {
779        T::head_append_many(tokens, enc);
780    }
781}
782
783/// Initializes each element of `out` by calling `f` for each slot.
784///
785/// On success, all elements in `out` are initialized and returned as `&mut [T]`.
786/// On failure or panic, already-initialized elements are dropped.
787#[inline]
788fn try_init_each<T, E, F>(out: &mut [MaybeUninit<T>], mut f: F) -> core::result::Result<&mut [T], E>
789where
790    F: FnMut() -> core::result::Result<T, E>,
791{
792    struct Guard<'a, T> {
793        buf: &'a mut [MaybeUninit<T>],
794        initialized: usize,
795    }
796    impl<T> Drop for Guard<'_, T> {
797        fn drop(&mut self) {
798            // SAFETY: the first `self.initialized` elements are guaranteed initialized.
799            unsafe {
800                let ptr = self.buf.as_mut_ptr().cast::<T>();
801                ptr::drop_in_place(ptr::slice_from_raw_parts_mut(ptr, self.initialized));
802            }
803        }
804    }
805
806    let mut guard = Guard { buf: out, initialized: 0 };
807    for x in guard.buf.iter_mut() {
808        x.write(f()?);
809        guard.initialized += 1;
810    }
811    let buf = guard.buf as *mut [MaybeUninit<T>] as *mut [T];
812    mem::forget(guard);
813    // SAFETY: all `len` elements are initialized.
814    Ok(unsafe { &mut *buf })
815}
816
817#[cfg(test)]
818mod tests {
819    use super::*;
820    use crate::{SolType, sol_data};
821    use alloy_primitives::B256;
822
823    macro_rules! assert_type_check {
824        ($sol:ty, $token:expr $(,)?) => {
825            assert!(<$sol>::type_check($token).is_ok())
826        };
827    }
828
829    macro_rules! assert_not_type_check {
830        ($sol:ty, $token:expr $(,)?) => {
831            assert!(<$sol>::type_check($token).is_err())
832        };
833    }
834
835    #[test]
836    fn test_type_check() {
837        assert_type_check!(
838            (sol_data::Uint<256>, sol_data::Bool),
839            &(WordToken(B256::default()), WordToken(B256::default())),
840        );
841
842        // TODO(tests): more like this where we test type check internal logic
843        assert_not_type_check!(sol_data::Uint<8>, &Word::repeat_byte(0x11).into());
844        assert_not_type_check!(sol_data::Bool, &B256::repeat_byte(0x11).into());
845        assert_not_type_check!(sol_data::FixedBytes<31>, &B256::repeat_byte(0x11).into());
846
847        assert_type_check!(
848            (sol_data::Uint<32>, sol_data::Bool),
849            &(WordToken(B256::default()), WordToken(B256::default())),
850        );
851
852        assert_type_check!(
853            sol_data::Array<sol_data::Bool>,
854            &DynSeqToken(vec![WordToken(B256::default()), WordToken(B256::default()),]),
855        );
856
857        assert_type_check!(
858            sol_data::Array<sol_data::Bool>,
859            &DynSeqToken(vec![WordToken(B256::default()), WordToken(B256::default()),]),
860        );
861        assert_type_check!(
862            sol_data::Array<sol_data::Address>,
863            &DynSeqToken(vec![WordToken(B256::default()), WordToken(B256::default()),]),
864        );
865
866        assert_type_check!(
867            sol_data::FixedArray<sol_data::Bool, 2>,
868            &FixedSeqToken::<_, 2>([
869                WordToken(B256::default()),
870                WordToken(B256::default()),
871            ]),
872        );
873
874        assert_type_check!(
875            sol_data::FixedArray<sol_data::Address, 2>,
876            &FixedSeqToken::<_, 2>([
877                WordToken(B256::default()),
878                WordToken(B256::default()),
879            ]),
880        );
881    }
882}