ink_primitives/sol/
types.rs1use alloy_sol_types::{
16 abi::{
17 self,
18 token::{
19 DynSeqToken,
20 FixedSeqToken,
21 PackedSeqToken,
22 WordToken,
23 },
24 },
25 private::SolTypeValue,
26 sol_data,
27 SolType as AlloySolType,
28};
29use core::ops::Deref;
30use impl_trait_for_tuples::impl_for_tuples;
31use ink_prelude::{
32 borrow::Cow,
33 boxed::Box,
34 string::String,
35 vec::Vec,
36};
37use itertools::Itertools;
38use paste::paste;
39use primitive_types::U256;
40
41use crate::types::Address;
42
43#[allow(private_bounds)]
72pub trait SolTypeDecode: Sized + private::Sealed {
73 type AlloyType: AlloySolType;
75
76 fn decode(data: &[u8]) -> Result<Self, alloy_sol_types::Error> {
78 abi::decode::<<Self::AlloyType as AlloySolType>::Token<'_>>(data)
79 .and_then(Self::detokenize)
80 }
81
82 fn detokenize(
84 token: <Self::AlloyType as AlloySolType>::Token<'_>,
85 ) -> Result<Self, alloy_sol_types::Error>;
86}
87
88#[allow(private_bounds)]
120pub trait SolTypeEncode: private::Sealed {
121 type AlloyType: AlloySolType;
123
124 fn encode(&self) -> Vec<u8> {
126 abi::encode(&self.tokenize())
127 }
128
129 fn tokenize(&self) -> <Self::AlloyType as AlloySolType>::Token<'_>;
131}
132
133macro_rules! impl_primitive_decode {
134 ($($ty: ty => $sol_ty: ty),+ $(,)*) => {
135 $(
136 impl SolTypeDecode for $ty {
137 type AlloyType = $sol_ty;
138
139 fn detokenize(token: <Self::AlloyType as AlloySolType>::Token<'_>) -> Result<Self, alloy_sol_types::Error> {
140 Ok(<Self::AlloyType as AlloySolType>::detokenize(token))
141 }
142 }
143 )*
144 };
145}
146
147macro_rules! impl_primitive_encode {
148 ($($ty: ty => $sol_ty: ty),+ $(,)*) => {
149 $(
150 impl SolTypeEncode for $ty where Self: SolTypeValue<$sol_ty> {
151 type AlloyType = $sol_ty;
152
153 fn tokenize(&self) -> <Self::AlloyType as AlloySolType>::Token<'_> {
154 <Self::AlloyType as AlloySolType>::tokenize(self)
155 }
156 }
157 )*
158 };
159}
160
161macro_rules! impl_primitive {
162 ($($ty: ty => $sol_ty: ty),+ $(,)*) => {
163 $(
164 impl_primitive_decode!($ty => $sol_ty);
165
166 impl_primitive_encode!($ty => $sol_ty);
167
168 impl private::Sealed for $ty {}
169 )*
170 };
171}
172
173macro_rules! impl_native_int {
174 ($($bits: literal),+$(,)*) => {
175 $(
176 impl_primitive! {
177 paste!([<i $bits>]) => sol_data::Int<$bits>,
179 paste!([<u $bits>]) => sol_data::Uint<$bits>,
181 }
182 )*
183 };
184}
185
186impl_native_int!(8, 16, 32, 64, 128);
187
188impl_primitive! {
189 bool => sol_data::Bool,
191 String => sol_data::String,
193}
194
195impl SolTypeDecode for Box<str> {
197 type AlloyType = sol_data::String;
198
199 fn detokenize(
200 token: <Self::AlloyType as AlloySolType>::Token<'_>,
201 ) -> Result<Self, alloy_sol_types::Error> {
202 Ok(Box::from(core::str::from_utf8(token.0).map_err(|_| {
203 alloy_sol_types::Error::type_check_fail(token.0, "string")
204 })?))
205 }
206}
207
208impl SolTypeEncode for Box<str> {
209 type AlloyType = sol_data::String;
210
211 fn tokenize(&self) -> <Self::AlloyType as AlloySolType>::Token<'_> {
212 PackedSeqToken(self.as_bytes())
213 }
214}
215
216impl private::Sealed for Box<str> {}
217
218impl SolTypeDecode for Address {
220 type AlloyType = sol_data::Address;
221
222 fn detokenize(
223 token: <Self::AlloyType as AlloySolType>::Token<'_>,
224 ) -> Result<Self, alloy_sol_types::Error> {
225 Ok(Address::from_slice(&token.0 .0[12..]))
230 }
231}
232
233impl SolTypeEncode for Address {
234 type AlloyType = sol_data::Address;
235
236 fn tokenize(&self) -> <Self::AlloyType as AlloySolType>::Token<'_> {
237 let mut word = [0; 32];
241 word[12..].copy_from_slice(self.0.as_slice());
242 WordToken::from(word)
243 }
244}
245
246impl private::Sealed for Address {}
247
248impl SolTypeDecode for U256 {
250 type AlloyType = sol_data::Uint<256>;
251
252 fn detokenize(
253 token: <Self::AlloyType as AlloySolType>::Token<'_>,
254 ) -> Result<Self, alloy_sol_types::Error> {
255 Ok(U256::from_big_endian(token.0 .0.as_slice()))
256 }
257}
258
259impl SolTypeEncode for U256 {
260 type AlloyType = sol_data::Uint<256>;
261
262 fn tokenize(&self) -> <Self::AlloyType as AlloySolType>::Token<'_> {
263 WordToken::from(self.to_big_endian())
268 }
269}
270
271impl private::Sealed for U256 {}
272
273impl<T: SolTypeDecode, const N: usize> SolTypeDecode for [T; N] {
275 type AlloyType = sol_data::FixedArray<T::AlloyType, N>;
276
277 fn detokenize(
278 token: <Self::AlloyType as AlloySolType>::Token<'_>,
279 ) -> Result<Self, alloy_sol_types::Error> {
280 token
286 .0
287 .into_iter()
288 .map(<T as SolTypeDecode>::detokenize)
289 .process_results(|iter| iter.collect_array())?
290 .ok_or_else(|| {
291 alloy_sol_types::Error::custom(ink_prelude::format!(
292 "ABI decoding failed: {}",
293 Self::AlloyType::SOL_NAME
294 ))
295 })
296 }
297}
298
299impl<T: SolTypeEncode, const N: usize> SolTypeEncode for [T; N] {
300 type AlloyType = sol_data::FixedArray<T::AlloyType, N>;
301
302 fn tokenize(&self) -> <Self::AlloyType as AlloySolType>::Token<'_> {
303 FixedSeqToken(core::array::from_fn(|i| {
306 <T as SolTypeEncode>::tokenize(&self[i])
307 }))
308 }
309}
310
311impl<T: private::Sealed, const N: usize> private::Sealed for [T; N] {}
312
313impl<T: SolTypeDecode> SolTypeDecode for Vec<T> {
315 type AlloyType = sol_data::Array<T::AlloyType>;
316
317 fn detokenize(
318 token: <Self::AlloyType as AlloySolType>::Token<'_>,
319 ) -> Result<Self, alloy_sol_types::Error> {
320 token
323 .0
324 .into_iter()
325 .map(<T as SolTypeDecode>::detokenize)
326 .collect()
327 }
328}
329
330impl<T: SolTypeEncode> SolTypeEncode for Vec<T> {
331 type AlloyType = sol_data::Array<T::AlloyType>;
332
333 fn tokenize(&self) -> <Self::AlloyType as AlloySolType>::Token<'_> {
334 DynSeqToken(self.iter().map(<T as SolTypeEncode>::tokenize).collect())
337 }
338}
339
340impl<T: private::Sealed> private::Sealed for Vec<T> {}
341
342impl<T: SolTypeDecode> SolTypeDecode for Box<[T]> {
344 type AlloyType = sol_data::Array<T::AlloyType>;
345
346 fn detokenize(
347 token: <Self::AlloyType as AlloySolType>::Token<'_>,
348 ) -> Result<Self, alloy_sol_types::Error> {
349 token
352 .0
353 .into_iter()
354 .map(<T as SolTypeDecode>::detokenize)
355 .collect()
356 }
357}
358
359impl<T: SolTypeEncode> SolTypeEncode for Box<[T]> {
360 type AlloyType = sol_data::Array<T::AlloyType>;
361
362 fn tokenize(&self) -> <Self::AlloyType as AlloySolType>::Token<'_> {
363 DynSeqToken(self.iter().map(<T as SolTypeEncode>::tokenize).collect())
366 }
367}
368
369impl<T: private::Sealed> private::Sealed for Box<[T]> {}
370
371#[impl_for_tuples(12)]
375impl SolTypeDecode for Tuple {
376 for_tuples!( type AlloyType = ( #( Tuple::AlloyType ),* ); );
377
378 #[allow(clippy::unused_unit)]
379 fn detokenize(
380 token: <Self::AlloyType as AlloySolType>::Token<'_>,
381 ) -> Result<Self, alloy_sol_types::Error> {
382 Ok(for_tuples! { ( #( <Tuple as SolTypeDecode>::detokenize(token.Tuple)? ),* ) })
385 }
386}
387
388#[impl_for_tuples(12)]
389impl SolTypeEncode for Tuple {
390 for_tuples!( type AlloyType = ( #( Tuple::AlloyType ),* ); );
391
392 #[allow(clippy::unused_unit)]
393 fn tokenize(&self) -> <Self::AlloyType as AlloySolType>::Token<'_> {
394 for_tuples!( ( #( <Tuple as SolTypeEncode>::tokenize(&self.Tuple) ),* ) );
397 }
398}
399
400#[impl_for_tuples(12)]
401impl private::Sealed for Tuple {}
402
403macro_rules! impl_refs_encode {
405 ($([$($gen:tt)*] $ty: ty), +$(,)*) => {
406 $(
407
408 impl<$($gen)* T: SolTypeEncode> SolTypeEncode for $ty {
409 type AlloyType = T::AlloyType;
410
411 fn tokenize(&self) -> <Self::AlloyType as AlloySolType>::Token<'_> {
412 <T as SolTypeEncode>::tokenize(self)
413 }
414 }
415
416 impl<$($gen)* T: private::Sealed> private::Sealed for $ty {}
417 )*
418 };
419}
420
421impl_refs_encode! {
422 ['a,] &'a T,
423 ['a,] &'a mut T,
424 [] Box<T>,
425}
426
427impl<T: SolTypeEncode + Clone> SolTypeEncode for Cow<'_, T> {
428 type AlloyType = T::AlloyType;
429
430 fn tokenize(&self) -> <Self::AlloyType as AlloySolType>::Token<'_> {
431 <T as SolTypeEncode>::tokenize(self.deref())
432 }
433}
434
435impl<T: private::Sealed + Clone> private::Sealed for Cow<'_, T> {}
436
437macro_rules! impl_str_ref_encode {
439 ($($ty: ty),+ $(,)*) => {
440 $(
441 impl SolTypeEncode for $ty {
442 type AlloyType = sol_data::String;
443
444 fn tokenize(&self) -> <Self::AlloyType as AlloySolType>::Token<'_> {
445 PackedSeqToken(self.as_bytes())
446 }
447 }
448
449 impl private::Sealed for $ty {}
450 )*
451 };
452}
453
454impl_str_ref_encode!(&str, &mut str);
455
456macro_rules! impl_slice_ref_encode {
457 ($($ty: ty),+ $(,)*) => {
458 $(
459 impl<T: SolTypeEncode> SolTypeEncode for $ty {
460 type AlloyType = sol_data::Array<T::AlloyType>;
461
462 fn tokenize(&self) -> <Self::AlloyType as AlloySolType>::Token<'_> {
463 DynSeqToken(self.iter().map(<T as SolTypeEncode>::tokenize).collect())
466 }
467 }
468
469 impl<T: private::Sealed> private::Sealed for $ty {}
470 )*
471 };
472}
473
474impl_slice_ref_encode!(&[T], &mut [T]);
475
476pub(super) mod private {
477 pub trait Sealed {}
479}