1use alloy_sol_types::{
16 abi::{
17 token::{
18 DynSeqToken,
19 FixedSeqToken,
20 PackedSeqToken,
21 Token,
22 WordToken,
23 },
24 Encoder,
25 },
26 Word,
27};
28use ink_prelude::vec::Vec;
29
30pub trait Encodable: private::Sealed {
48 const DYNAMIC: bool;
50
51 fn head_words(&self) -> usize;
53
54 fn tail_words(&self) -> usize;
56
57 #[inline(always)]
59 fn total_words(&self) -> usize {
60 self.head_words() + self.tail_words()
61 }
62
63 fn head_append(&self, encoder: &mut Encoder);
65
66 fn tail_append(&self, encoder: &mut Encoder);
68
69 fn encode(&self, encoder: &mut Encoder) {
71 encoder.push_offset(Encodable::head_words(self));
74 Encodable::head_append(self, encoder);
75 if <Self as Encodable>::DYNAMIC {
76 encoder.bump_offset(Encodable::tail_words(self));
78 Encodable::tail_append(self, encoder);
79 }
80 encoder.pop_offset();
82 }
83}
84
85macro_rules! impl_encodable_for_token {
88 ($([$($gen:tt)*] $ty: ty),+ $(,)*) => {
89 $(
90 impl<$($gen)*> Encodable for $ty {
91 const DYNAMIC: bool = <$ty as Token>::DYNAMIC;
92
93 fn head_words(&self) -> usize {
94 Token::head_words(self)
95 }
96
97 fn tail_words(&self) -> usize {
98 Token::tail_words(self)
99 }
100
101 fn head_append(&self, encoder: &mut Encoder) {
102 Token::head_append(self, encoder);
103 }
104
105 fn tail_append(&self, encoder: &mut Encoder) {
106 Token::tail_append(self, encoder);
107 }
108 }
109
110 impl<$($gen)*> private::Sealed for $ty {}
111 )+
112 };
113}
114
115impl_encodable_for_token! {
116 [] WordToken,
117 [] PackedSeqToken<'_>,
118 [T: for<'a> Token<'a>, const N: usize] FixedSeqToken<T, N>,
119 [T: for<'a> Token<'a>] DynSeqToken<T>,
120}
121
122#[derive(Debug)]
125pub enum TokenOrDefault<T, D> {
126 Token(T),
127 Default(D),
128}
129
130#[derive(Debug, Clone, Copy, PartialEq, Eq)]
132pub struct FixedSizeDefault(usize);
133
134impl FixedSizeDefault {
135 pub const EMPTY: Self = Self(0);
137
138 pub const WORD: Self = Self(1);
140
141 pub const fn words(size: usize) -> Self {
143 Self(size)
144 }
145}
146
147#[derive(Debug, Clone, Copy, PartialEq, Eq)]
149pub struct DynSizeDefault;
150
151impl Encodable for FixedSizeDefault {
152 const DYNAMIC: bool = false;
153
154 fn head_words(&self) -> usize {
155 self.0
157 }
158
159 fn tail_words(&self) -> usize {
160 0
162 }
163
164 fn head_append(&self, encoder: &mut Encoder) {
165 match self.0 {
166 0 => (),
167 1 => {
168 encoder.append_word(Word::from([0u8; 32]));
170 }
171 size => {
172 let mut counter = 0;
176 while counter < size {
177 encoder.append_word(Word::from([0u8; 32]));
178 counter += 1;
179 }
180 }
181 }
182 }
183
184 fn tail_append(&self, _: &mut Encoder) {}
185}
186
187impl private::Sealed for FixedSizeDefault {}
188
189impl Encodable for DynSizeDefault {
190 const DYNAMIC: bool = true;
191
192 fn head_words(&self) -> usize {
193 1
195 }
196
197 fn tail_words(&self) -> usize {
198 1
200 }
201
202 fn head_append(&self, encoder: &mut Encoder) {
203 encoder.append_indirection();
205 }
206
207 fn tail_append(&self, encoder: &mut Encoder) {
208 encoder.append_seq_len(0);
209 }
210}
211
212impl private::Sealed for DynSizeDefault {}
213
214impl<T, D> Encodable for TokenOrDefault<T, D>
215where
216 T: Encodable,
217 D: Encodable,
218{
219 const DYNAMIC: bool = T::DYNAMIC;
220
221 fn head_words(&self) -> usize {
222 match self {
223 TokenOrDefault::Token(token) => token.head_words(),
224 TokenOrDefault::Default(default) => default.head_words(),
225 }
226 }
227
228 fn tail_words(&self) -> usize {
229 match self {
230 TokenOrDefault::Token(token) => token.tail_words(),
231 TokenOrDefault::Default(default) => default.tail_words(),
232 }
233 }
234
235 fn head_append(&self, encoder: &mut Encoder) {
236 match self {
237 TokenOrDefault::Token(token) => token.head_append(encoder),
238 TokenOrDefault::Default(default) => default.head_append(encoder),
239 }
240 }
241
242 fn tail_append(&self, encoder: &mut Encoder) {
243 match self {
244 TokenOrDefault::Token(token) => token.tail_append(encoder),
245 TokenOrDefault::Default(default) => default.tail_append(encoder),
246 }
247 }
248}
249
250impl<T, D> private::Sealed for TokenOrDefault<T, D> {}
251
252impl<T, const N: usize> Encodable for [T; N]
257where
258 T: Encodable,
259{
260 const DYNAMIC: bool = T::DYNAMIC;
261
262 fn head_words(&self) -> usize {
263 if Self::DYNAMIC {
264 1
266 } else {
267 self.iter().map(T::total_words).sum()
269 }
270 }
271
272 fn tail_words(&self) -> usize {
273 if Self::DYNAMIC {
274 self.iter().map(T::total_words).sum()
276 } else {
277 0
278 }
279 }
280
281 fn head_append(&self, encoder: &mut Encoder) {
282 if Self::DYNAMIC {
283 encoder.append_indirection();
285 } else {
286 for inner in self {
288 inner.head_append(encoder);
289 }
290 }
291 }
292
293 fn tail_append(&self, encoder: &mut Encoder) {
294 if Self::DYNAMIC {
296 encode_sequence(self, encoder);
297 }
298 }
299}
300
301impl<T, const N: usize> private::Sealed for [T; N] {}
302
303impl<T> Encodable for Vec<T>
308where
309 T: Encodable,
310{
311 const DYNAMIC: bool = true;
312
313 fn head_words(&self) -> usize {
314 1
316 }
317
318 fn tail_words(&self) -> usize {
319 1 + self.iter().map(T::total_words).sum::<usize>()
321 }
322
323 fn head_append(&self, encoder: &mut Encoder) {
324 encoder.append_indirection();
326 }
327
328 fn tail_append(&self, encoder: &mut Encoder) {
329 encoder.append_seq_len(self.len());
331
332 encode_sequence(self, encoder);
334 }
335}
336
337impl<T> private::Sealed for Vec<T> {}
338
339fn encode_sequence<T>(tokens: &[T], encoder: &mut Encoder)
346where
347 T: Encodable,
348{
349 encoder.push_offset(tokens.iter().map(T::head_words).sum());
350 for inner in tokens {
351 inner.head_append(encoder);
352 encoder.bump_offset(inner.tail_words());
353 }
354 for inner in tokens {
355 inner.tail_append(encoder);
356 }
357 encoder.pop_offset();
358}
359
360pub trait EncodableParams: private::Sealed {
366 fn encode_params(&self, encoder: &mut Encoder);
368}
369
370macro_rules! impl_encodable_params {
373 ($source: ident, $encoder: ident => ($($ty:ident),+$(,)*)) => {
374 let ($($ty,)+) = $source;
375 $encoder.push_offset(0 $( + $ty.head_words() )+);
376
377 $(
378 $ty.head_append($encoder);
379 $encoder.bump_offset($ty.tail_words());
380 )+
381
382 $(
383 $ty.tail_append($encoder);
384 )+
385
386 $encoder.pop_offset();
387 };
388}
389
390macro_rules! impl_encodable {
397 ($($ty:ident),+) => {
398 #[allow(non_snake_case)]
399 impl<$($ty: Encodable,)+> Encodable for ($($ty,)+) {
400 const DYNAMIC: bool = $(<$ty as Encodable>::DYNAMIC )||+;
401
402 #[inline]
403 fn head_words(&self) -> usize {
404 if Self::DYNAMIC {
405 1
407 } else {
408 let ($($ty,)+) = self;
410 0 $( + $ty.total_words() )+
411 }
412 }
413
414 #[inline]
415 fn tail_words(&self) -> usize {
416 if Self::DYNAMIC {
417 let ($($ty,)+) = self;
419 0 $( + $ty.total_words() )+
420 } else {
421 0
422 }
423 }
424
425 #[inline]
426 fn head_append(&self, encoder: &mut Encoder) {
427 if Self::DYNAMIC {
428 encoder.append_indirection();
429 } else {
430 let ($($ty,)+) = self;
431 $(
432 $ty.head_append(encoder);
433 )+
434 }
435 }
436
437 #[inline]
438 fn tail_append(&self, encoder: &mut Encoder) {
439 if Self::DYNAMIC {
440 impl_encodable_params!(self, encoder => ($($ty,)+));
441 }
442 }
443 }
444
445 #[allow(non_snake_case)]
446 impl<$($ty: Encodable,)+> EncodableParams for ($($ty,)+) {
447 fn encode_params(&self, encoder: &mut Encoder) {
448 impl_encodable_params!(self, encoder => ($($ty,)+));
449 }
450 }
451
452 impl<$($ty: Encodable,)+> private::Sealed for ($($ty,)+) {}
453 };
454}
455
456impl_all_tuples!(@nonempty impl_encodable);
457
458impl Encodable for () {
463 const DYNAMIC: bool = false;
464
465 #[inline]
466 fn head_words(&self) -> usize {
467 0
468 }
469
470 #[inline]
471 fn tail_words(&self) -> usize {
472 0
473 }
474
475 #[inline]
476 fn head_append(&self, _: &mut Encoder) {}
477
478 #[inline]
479 fn tail_append(&self, _: &mut Encoder) {}
480
481 #[inline]
482 fn encode(&self, _: &mut Encoder) {}
483}
484
485impl EncodableParams for () {
486 fn encode_params(&self, _: &mut Encoder) {}
487}
488
489impl private::Sealed for () {}
490
491pub(super) mod private {
492 pub trait Sealed {}
494}