1use core::{
16 clone::Clone,
17 ops::Deref,
18};
19
20use alloy_sol_types::{
21 abi::{
22 self,
23 token::{
24 PackedSeqToken,
25 WordToken,
26 },
27 Encoder,
28 },
29 sol_data,
30 SolType as AlloySolType,
31};
32use impl_trait_for_tuples::impl_for_tuples;
33use ink_prelude::{
34 borrow::{
35 Cow,
36 ToOwned,
37 },
38 boxed::Box,
39 string::String,
40 vec::Vec,
41};
42use itertools::Itertools;
43use paste::paste;
44use primitive_types::U256;
45
46use crate::{
47 sol::{
48 encodable::{
49 DynSizeDefault,
50 Encodable,
51 FixedSizeDefault,
52 TokenOrDefault,
53 },
54 Error,
55 },
56 types::Address,
57};
58
59pub trait SolTypeDecode: Sized + private::Sealed {
88 type AlloyType: AlloySolType;
90
91 fn decode(data: &[u8]) -> Result<Self, Error> {
93 abi::decode::<<Self::AlloyType as AlloySolType>::Token<'_>>(data)
94 .map_err(Error::from)
95 .and_then(Self::detokenize)
96 }
97
98 fn detokenize(
100 token: <Self::AlloyType as AlloySolType>::Token<'_>,
101 ) -> Result<Self, Error>;
102}
103
104pub trait SolTypeEncode: SolTokenType + private::Sealed {
136 type AlloyType: AlloySolType;
138
139 const DEFAULT_VALUE: Self::DefaultType;
141
142 fn encode(&self) -> Vec<u8> {
144 let token = self.tokenize();
145 let mut encoder = Encoder::with_capacity(token.total_words());
146 token.encode(&mut encoder);
147 encoder.into_bytes()
148 }
149
150 fn tokenize(&self) -> Self::TokenType<'_>;
152}
153
154pub trait SolTokenType: private::Sealed {
187 type TokenType<'enc>: Encodable;
189
190 type DefaultType: Encodable;
192}
193
194macro_rules! impl_primitive_decode {
195 ($($ty: ty => $sol_ty: ty),+ $(,)*) => {
196 $(
197 impl SolTypeDecode for $ty {
198 type AlloyType = $sol_ty;
199
200 fn detokenize(token: <Self::AlloyType as AlloySolType>::Token<'_>) -> Result<Self, Error> {
201 Ok(<Self::AlloyType as AlloySolType>::detokenize(token))
202 }
203 }
204 )*
205 };
206}
207
208macro_rules! impl_primitive_encode {
209 ($($ty: ty => ($sol_ty: ty, $default_ty: ty, $default_value: expr)),+ $(,)*) => {
210 $(
211 impl SolTypeEncode for $ty {
212 type AlloyType = $sol_ty;
213
214 const DEFAULT_VALUE: Self::DefaultType = $default_value;
215
216 fn tokenize(&self) -> Self::TokenType<'_> {
217 <Self::AlloyType as AlloySolType>::tokenize(self)
218 }
219 }
220
221 impl SolTokenType for $ty {
222 type TokenType<'enc> = <$sol_ty as AlloySolType>::Token<'enc>;
223
224 type DefaultType = $default_ty;
225 }
226 )*
227 };
228}
229
230macro_rules! impl_primitive {
231 ($($ty: ty => ($sol_ty: ty, $default_ty: ty, $default_value: expr)),+ $(,)*) => {
232 $(
233 impl_primitive_decode!($ty => $sol_ty);
234
235 impl_primitive_encode!($ty => ($sol_ty, $default_ty, $default_value));
236
237 impl private::Sealed for $ty {}
238 )*
239 };
240}
241
242macro_rules! impl_native_int {
243 ($($bits: literal),+$(,)*) => {
244 $(
245 impl_primitive! {
246 paste!([<i $bits>]) => (sol_data::Int<$bits>, FixedSizeDefault, FixedSizeDefault::WORD),
248 paste!([<u $bits>]) => (sol_data::Uint<$bits>, FixedSizeDefault, FixedSizeDefault::WORD),
250 }
251 )*
252 };
253}
254
255impl_native_int!(8, 16, 32, 64, 128);
256
257impl_primitive! {
258 bool => (sol_data::Bool, FixedSizeDefault, FixedSizeDefault::WORD),
260 String => (sol_data::String, DynSizeDefault, DynSizeDefault),
262}
263
264impl SolTypeDecode for Box<str> {
266 type AlloyType = sol_data::String;
267
268 fn detokenize(
269 token: <Self::AlloyType as AlloySolType>::Token<'_>,
270 ) -> Result<Self, Error> {
271 Ok(Box::from(core::str::from_utf8(token.0).map_err(|_| Error)?))
272 }
273}
274
275impl SolTypeEncode for Box<str> {
276 type AlloyType = sol_data::String;
277
278 const DEFAULT_VALUE: Self::DefaultType = DynSizeDefault;
279
280 fn tokenize(&self) -> Self::TokenType<'_> {
281 PackedSeqToken(self.as_bytes())
282 }
283}
284
285impl SolTokenType for Box<str> {
286 type TokenType<'enc> = PackedSeqToken<'enc>;
287
288 type DefaultType = DynSizeDefault;
289}
290
291impl private::Sealed for Box<str> {}
292
293impl SolTypeDecode for Address {
295 type AlloyType = sol_data::Address;
296
297 fn detokenize(
298 token: <Self::AlloyType as AlloySolType>::Token<'_>,
299 ) -> Result<Self, Error> {
300 Ok(Address::from_slice(&token.0 .0[12..]))
305 }
306}
307
308impl SolTypeEncode for Address {
309 type AlloyType = sol_data::Address;
310
311 const DEFAULT_VALUE: Self::DefaultType = FixedSizeDefault::WORD;
312
313 fn tokenize(&self) -> Self::TokenType<'_> {
314 let mut word = [0; 32];
318 word[12..].copy_from_slice(self.0.as_slice());
319 WordToken::from(word)
320 }
321}
322
323impl SolTokenType for Address {
324 type TokenType<'enc> = WordToken;
325
326 type DefaultType = FixedSizeDefault;
327}
328
329impl private::Sealed for Address {}
330
331impl SolTypeDecode for U256 {
333 type AlloyType = sol_data::Uint<256>;
334
335 fn detokenize(
336 token: <Self::AlloyType as AlloySolType>::Token<'_>,
337 ) -> Result<Self, Error> {
338 Ok(U256::from_big_endian(token.0 .0.as_slice()))
339 }
340}
341
342impl SolTypeEncode for U256 {
343 type AlloyType = sol_data::Uint<256>;
344
345 const DEFAULT_VALUE: Self::DefaultType = FixedSizeDefault::WORD;
346
347 fn tokenize(&self) -> Self::TokenType<'_> {
348 WordToken::from(self.to_big_endian())
353 }
354}
355
356impl SolTokenType for U256 {
357 type TokenType<'enc> = WordToken;
358
359 type DefaultType = FixedSizeDefault;
360}
361
362impl private::Sealed for U256 {}
363
364impl<T: SolTypeDecode, const N: usize> SolTypeDecode for [T; N] {
366 type AlloyType = sol_data::FixedArray<T::AlloyType, N>;
367
368 fn detokenize(
369 token: <Self::AlloyType as AlloySolType>::Token<'_>,
370 ) -> Result<Self, Error> {
371 token
377 .0
378 .into_iter()
379 .map(<T as SolTypeDecode>::detokenize)
380 .process_results(|iter| iter.collect_array())?
381 .ok_or(Error)
382 }
383}
384
385impl<T: SolTypeEncode, const N: usize> SolTypeEncode for [T; N] {
386 type AlloyType = sol_data::FixedArray<T::AlloyType, N>;
387
388 const DEFAULT_VALUE: Self::DefaultType = [T::DEFAULT_VALUE; N];
389
390 fn tokenize(&self) -> Self::TokenType<'_> {
391 core::array::from_fn(|i| <T as SolTypeEncode>::tokenize(&self[i]))
394 }
395}
396
397impl<T: SolTokenType, const N: usize> SolTokenType for [T; N] {
398 type TokenType<'enc> = [T::TokenType<'enc>; N];
399
400 type DefaultType = [T::DefaultType; N];
401}
402
403impl<T: private::Sealed, const N: usize> private::Sealed for [T; N] {}
404
405impl<T: SolTypeDecode> SolTypeDecode for Vec<T> {
407 type AlloyType = sol_data::Array<T::AlloyType>;
408
409 fn detokenize(
410 token: <Self::AlloyType as AlloySolType>::Token<'_>,
411 ) -> Result<Self, Error> {
412 token
415 .0
416 .into_iter()
417 .map(<T as SolTypeDecode>::detokenize)
418 .collect()
419 }
420}
421
422impl<T: SolTypeEncode> SolTypeEncode for Vec<T> {
423 type AlloyType = sol_data::Array<T::AlloyType>;
424
425 const DEFAULT_VALUE: Self::DefaultType = DynSizeDefault;
426
427 fn tokenize(&self) -> Self::TokenType<'_> {
428 self.iter().map(<T as SolTypeEncode>::tokenize).collect()
431 }
432}
433
434impl<T: SolTokenType> SolTokenType for Vec<T> {
435 type TokenType<'enc> = Vec<T::TokenType<'enc>>;
436
437 type DefaultType = DynSizeDefault;
438}
439
440impl<T: private::Sealed> private::Sealed for Vec<T> {}
441
442impl<T: SolTypeDecode> SolTypeDecode for Box<[T]> {
444 type AlloyType = sol_data::Array<T::AlloyType>;
445
446 fn detokenize(
447 token: <Self::AlloyType as AlloySolType>::Token<'_>,
448 ) -> Result<Self, Error> {
449 token
452 .0
453 .into_iter()
454 .map(<T as SolTypeDecode>::detokenize)
455 .collect()
456 }
457}
458
459impl<T: SolTypeEncode> SolTypeEncode for Box<[T]> {
460 type AlloyType = sol_data::Array<T::AlloyType>;
461
462 const DEFAULT_VALUE: Self::DefaultType = DynSizeDefault;
463
464 fn tokenize(&self) -> Self::TokenType<'_> {
465 self.iter().map(<T as SolTypeEncode>::tokenize).collect()
468 }
469}
470
471impl<T: SolTokenType> SolTokenType for Box<[T]> {
472 type TokenType<'enc> = Vec<T::TokenType<'enc>>;
473
474 type DefaultType = DynSizeDefault;
475}
476
477impl<T: private::Sealed> private::Sealed for Box<[T]> {}
478
479impl<T> SolTypeDecode for Cow<'_, [T]>
482where
483 T: SolTypeDecode + Clone,
484 [T]: ToOwned,
485{
486 type AlloyType = sol_data::Array<T::AlloyType>;
487
488 fn detokenize(
489 token: <Self::AlloyType as AlloySolType>::Token<'_>,
490 ) -> Result<Self, Error> {
491 token
494 .0
495 .into_iter()
496 .map(<T as SolTypeDecode>::detokenize)
497 .collect()
498 }
499}
500
501impl<T> SolTypeEncode for Cow<'_, [T]>
502where
503 T: SolTypeEncode + Clone,
504 [T]: ToOwned,
505{
506 type AlloyType = sol_data::Array<T::AlloyType>;
507
508 const DEFAULT_VALUE: Self::DefaultType = DynSizeDefault;
509
510 fn tokenize(&self) -> Self::TokenType<'_> {
511 self.iter().map(<T as SolTypeEncode>::tokenize).collect()
514 }
515}
516
517impl<T> SolTokenType for Cow<'_, [T]>
518where
519 T: SolTokenType + Clone,
520 [T]: ToOwned,
521{
522 type TokenType<'enc> = Vec<T::TokenType<'enc>>;
523
524 type DefaultType = DynSizeDefault;
525}
526
527impl<T: private::Sealed> private::Sealed for Cow<'_, [T]> where [T]: ToOwned {}
528
529#[impl_for_tuples(12)]
533impl SolTypeDecode for Tuple {
534 for_tuples!( type AlloyType = ( #( Tuple::AlloyType ),* ); );
535
536 #[allow(clippy::unused_unit)]
537 fn detokenize(
538 token: <Self::AlloyType as AlloySolType>::Token<'_>,
539 ) -> Result<Self, Error> {
540 Ok(for_tuples! { ( #( <Tuple as SolTypeDecode>::detokenize(token.Tuple)? ),* ) })
543 }
544}
545
546#[impl_for_tuples(12)]
547impl SolTypeEncode for Tuple {
548 for_tuples!( type AlloyType = ( #( Tuple::AlloyType ),* ); );
549
550 const DEFAULT_VALUE: Self::DefaultType =
551 (for_tuples! { #( Tuple::DEFAULT_VALUE ),* });
552
553 #[allow(clippy::unused_unit)]
554 fn tokenize(&self) -> Self::TokenType<'_> {
555 for_tuples!( ( #( <Tuple as SolTypeEncode>::tokenize(&self.Tuple) ),* ) );
558 }
559}
560
561macro_rules! impl_sol_token_type {
566 ( $($ty: ident),* ) => {
567 impl<$( $ty: SolTokenType, )*> SolTokenType for ( $( $ty, )* ) {
568 type TokenType<'enc> = ( $( $ty ::TokenType<'enc>, )* );
569
570 type DefaultType = ( $( $ty ::DefaultType, )* );
571 }
572 };
573}
574
575impl_all_tuples!(impl_sol_token_type);
576
577#[impl_for_tuples(12)]
578impl private::Sealed for Tuple {}
579
580impl<T: SolTypeDecode> SolTypeDecode for Option<T> {
582 type AlloyType = (sol_data::Bool, T::AlloyType);
583
584 fn detokenize(
585 token: <Self::AlloyType as AlloySolType>::Token<'_>,
586 ) -> Result<Self, Error> {
587 let flag = bool::detokenize(token.0)?;
588 let value = T::detokenize(token.1)?;
589 Ok(if flag { Some(value) } else { None })
590 }
591}
592
593impl<T> SolTypeEncode for Option<T>
594where
595 T: SolTypeEncode,
596{
597 type AlloyType = (sol_data::Bool, T::AlloyType);
598
599 const DEFAULT_VALUE: Self::DefaultType = (FixedSizeDefault::WORD, T::DEFAULT_VALUE);
600
601 fn tokenize(&self) -> Self::TokenType<'_> {
602 match self {
603 Some(value) => (true.tokenize(), TokenOrDefault::Token(value.tokenize())),
604 None => (false.tokenize(), TokenOrDefault::Default(T::DEFAULT_VALUE)),
605 }
606 }
607}
608
609impl<T: SolTokenType> SolTokenType for Option<T> {
610 type TokenType<'enc> = (
611 WordToken,
612 TokenOrDefault<T::TokenType<'enc>, T::DefaultType>,
613 );
614
615 type DefaultType = (FixedSizeDefault, T::DefaultType);
616}
617
618impl<T: private::Sealed> private::Sealed for Option<T> {}
619
620macro_rules! impl_refs_encode {
622 ($($ty: ty), +$(,)*) => {
623 $(
624 impl<T: SolTypeEncode> SolTypeEncode for $ty {
625 type AlloyType = T::AlloyType;
626
627 const DEFAULT_VALUE: Self::DefaultType = T::DEFAULT_VALUE;
628
629 fn tokenize(&self) -> Self::TokenType<'_> {
630 <T as SolTypeEncode>::tokenize(self)
631 }
632 }
633
634 impl<T: SolTokenType> SolTokenType for $ty {
635 type TokenType<'enc> = T::TokenType<'enc>;
636
637 type DefaultType = T::DefaultType;
638 }
639
640 impl<T: private::Sealed> private::Sealed for $ty {}
641 )*
642 };
643}
644
645impl_refs_encode! {
646 &T,
647 &mut T,
648 Box<T>,
649}
650
651impl<T: SolTypeEncode + Clone> SolTypeEncode for Cow<'_, T> {
653 type AlloyType = T::AlloyType;
654
655 const DEFAULT_VALUE: Self::DefaultType = T::DEFAULT_VALUE;
656
657 fn tokenize(&self) -> Self::TokenType<'_> {
658 <T as SolTypeEncode>::tokenize(self.deref())
659 }
660}
661
662impl<T: SolTokenType + Clone> SolTokenType for Cow<'_, T> {
663 type TokenType<'enc> = T::TokenType<'enc>;
664
665 type DefaultType = T::DefaultType;
666}
667
668impl<T: private::Sealed + Clone> private::Sealed for Cow<'_, T> {}
669
670macro_rules! impl_str_ref_encode {
672 ($($ty: ty),+ $(,)*) => {
673 $(
674 impl SolTypeEncode for $ty {
675 type AlloyType = sol_data::String;
676
677 const DEFAULT_VALUE: Self::DefaultType = DynSizeDefault;
678
679 fn tokenize(&self) -> Self::TokenType<'_> {
680 PackedSeqToken(self.as_bytes())
681 }
682 }
683
684 impl SolTokenType for $ty {
685 type TokenType<'enc> = PackedSeqToken<'enc>;
686
687 type DefaultType = DynSizeDefault;
688 }
689
690 impl private::Sealed for $ty {}
691 )*
692 };
693}
694
695impl_str_ref_encode!(&str, &mut str, Cow<'_, str>);
696
697macro_rules! impl_slice_ref_encode {
699 ($($ty: ty),+ $(,)*) => {
700 $(
701 impl<T: SolTypeEncode> SolTypeEncode for $ty {
702 type AlloyType = sol_data::Array<T::AlloyType>;
703
704 const DEFAULT_VALUE: Self::DefaultType = DynSizeDefault;
705
706 fn tokenize(&self) -> Self::TokenType<'_> {
707 self.iter().map(<T as SolTypeEncode>::tokenize).collect()
710 }
711 }
712
713 impl<T: SolTokenType> SolTokenType for $ty {
714 type TokenType<'enc> = Vec<T::TokenType<'enc>>;
715
716 type DefaultType = DynSizeDefault;
717 }
718
719 impl<T: private::Sealed> private::Sealed for $ty {}
720 )*
721 };
722}
723
724impl_slice_ref_encode!(&[T], &mut [T]);
725
726pub(super) mod private {
727 pub trait Sealed {}
729}