alloy_dyn_abi/dynamic/
token.rs1use crate::{Decoder, DynSolValue, Error, Result, Word};
2use alloc::{borrow::Cow, boxed::Box, vec::Vec};
3use alloy_primitives::try_vec;
4use alloy_sol_types::abi::token::{PackedSeqToken, Token, WordToken};
5
6#[derive(Clone, Debug)]
13pub enum DynToken<'a> {
14 Word(Word),
16 FixedSeq(Cow<'a, [DynToken<'a>]>, usize),
18 DynSeq {
20 contents: Cow<'a, [DynToken<'a>]>,
22 #[doc(hidden)]
27 template: Option<Box<DynToken<'a>>>,
28 },
29 PackedSeq(&'a [u8]),
31}
32
33impl<T: Into<Word>> From<T> for DynToken<'_> {
34 #[inline]
35 fn from(value: T) -> Self {
36 Self::Word(value.into())
37 }
38}
39
40impl PartialEq<DynToken<'_>> for DynToken<'_> {
41 #[inline]
42 fn eq(&self, other: &DynToken<'_>) -> bool {
43 match (self, other) {
44 (Self::Word(l0), DynToken::Word(r0)) => l0 == r0,
45 (Self::FixedSeq(l0, l1), DynToken::FixedSeq(r0, r1)) => l0 == r0 && l1 == r1,
46 (
47 Self::DynSeq { contents: l_contents, .. },
48 DynToken::DynSeq { contents: r_contents, .. },
49 ) => l_contents == r_contents,
50 (Self::PackedSeq(l0), DynToken::PackedSeq(r0)) => l0 == r0,
51 _ => false,
52 }
53 }
54}
55
56impl Eq for DynToken<'_> {}
57
58impl<'a> DynToken<'a> {
59 pub fn minimum_words(&self) -> usize {
61 match self {
62 DynToken::Word(_) => 1,
63 DynToken::PackedSeq(_) => 1,
64 DynToken::FixedSeq(contents, _) => {
65 contents.iter().map(Self::minimum_words).sum::<usize>()
66 }
67 DynToken::DynSeq { .. } => 1,
68 }
69 }
70
71 #[inline]
73 pub fn from_fixed_seq(seq: &'a [DynSolValue]) -> Self {
74 let tokens = seq.iter().map(DynSolValue::tokenize).collect();
75 Self::FixedSeq(Cow::Owned(tokens), seq.len())
76 }
77
78 #[inline]
80 pub fn from_dyn_seq(seq: &'a [DynSolValue]) -> Self {
81 let tokens = seq.iter().map(DynSolValue::tokenize).collect();
82 Self::DynSeq { contents: Cow::Owned(tokens), template: None }
83 }
84
85 #[inline]
87 pub const fn as_word(&self) -> Option<Word> {
88 match self {
89 Self::Word(word) => Some(*word),
90 _ => None,
91 }
92 }
93
94 #[inline]
96 pub fn as_fixed_seq(&self) -> Option<(&[Self], usize)> {
97 match self {
98 Self::FixedSeq(tokens, size) => Some((tokens, *size)),
99 _ => None,
100 }
101 }
102
103 #[inline]
105 pub fn as_dynamic_seq(&self) -> Option<&[Self]> {
106 match self {
107 Self::DynSeq { contents, .. } => Some(contents),
108 _ => None,
109 }
110 }
111
112 #[inline]
114 pub fn as_token_seq(&self) -> Option<&[Self]> {
115 match self {
116 Self::FixedSeq(contents, _) | Self::DynSeq { contents, .. } => Some(contents),
117 _ => None,
118 }
119 }
120
121 #[inline]
123 pub const fn as_packed_seq(&self) -> Option<&[u8]> {
124 match self {
125 Self::PackedSeq(bytes) => Some(bytes),
126 _ => None,
127 }
128 }
129
130 #[inline]
132 pub fn is_dynamic(&self) -> bool {
133 match self {
134 Self::Word(_) => false,
135 Self::FixedSeq(inner, _) => inner.iter().any(Self::is_dynamic),
136 Self::DynSeq { .. } | Self::PackedSeq(_) => true,
137 }
138 }
139
140 #[inline]
142 pub(crate) fn decode_populate(&mut self, dec: &mut Decoder<'a>) -> Result<()> {
143 match self {
144 Self::Word(w) => *w = WordToken::decode_from(dec)?.0,
145 Self::FixedSeq(..) => {
146 let dynamic = self.is_dynamic();
147 let mut child = if dynamic { dec.take_indirection() } else { dec.raw_child() }?;
148
149 self.decode_sequence_populate(&mut child)?;
150
151 if !dynamic {
152 dec.take_offset_from(&child);
153 }
154 }
155 Self::DynSeq { contents, template } => {
156 let mut child = dec.take_indirection()?;
157 let size = child.take_offset()?;
158 if size == 0 {
159 debug_assert!(contents.is_empty());
161 return Ok(());
162 }
163
164 let template = template.take().expect("no template for dynamic sequence");
167
168 let mut child = child.raw_child()?;
173
174 if child.remaining_words() < template.minimum_words() * size {
178 return Err(alloy_sol_types::Error::Overrun.into());
179 }
180
181 let mut new_tokens = if size == 1 {
182 unsafe { Vec::from_raw_parts(Box::into_raw(template), 1, 1) }
184 } else {
185 try_vec![*template; size]?
186 };
187
188 for t in &mut new_tokens {
189 t.decode_populate(&mut child)?;
190 }
191
192 *contents = new_tokens.into();
193 }
194 Self::PackedSeq(buf) => *buf = PackedSeqToken::decode_from(dec)?.0,
195 }
196 Ok(())
197 }
198
199 #[inline]
202 pub(crate) fn decode_sequence_populate(&mut self, dec: &mut Decoder<'a>) -> Result<()> {
203 match self {
204 Self::FixedSeq(buf, size) => {
205 buf.to_mut().iter_mut().take(*size).try_for_each(|item| item.decode_populate(dec))
206 }
207 Self::DynSeq { .. } => self.decode_populate(dec),
208 _ => Err(Error::custom("Called decode_sequence_populate on non-sequence token")),
209 }
210 }
211
212 #[inline]
214 pub(crate) fn decode_single_populate(&mut self, dec: &mut Decoder<'a>) -> Result<()> {
215 self.decode_populate(dec)
219 }
220}