mod bytes;
mod types;
#[cfg(test)]
mod tests;
use core::ops::Deref;
use alloy_sol_types::{
sol_data,
SolType as AlloySolType,
};
use impl_trait_for_tuples::impl_for_tuples;
use ink_prelude::{
borrow::Cow,
boxed::Box,
string::String,
vec::Vec,
};
use primitive_types::{
H256,
U256,
};
pub use self::{
bytes::SolBytes,
types::{
SolTypeDecode,
SolTypeEncode,
},
};
pub use alloy_sol_types::Error;
use crate::types::{
AccountId,
Address,
Hash,
};
pub trait SolDecode {
type SolType: SolTypeDecode;
const SOL_NAME: &'static str =
<<Self::SolType as SolTypeDecode>::AlloyType as AlloySolType>::SOL_NAME;
fn decode(data: &[u8]) -> Result<Self, alloy_sol_types::Error>
where
Self: Sized,
{
<Self::SolType as SolTypeDecode>::decode(data).map(Self::from_sol_type)
}
fn from_sol_type(value: Self::SolType) -> Self;
}
pub trait SolEncode<'a> {
type SolType: SolTypeEncode;
const SOL_NAME: &'static str =
<<Self::SolType as SolTypeEncode>::AlloyType as AlloySolType>::SOL_NAME;
fn encode(&'a self) -> Vec<u8> {
<Self::SolType as SolTypeEncode>::encode(&self.to_sol_type())
}
fn to_sol_type(&'a self) -> Self::SolType;
}
macro_rules! impl_primitive_decode {
($($ty: ty),+ $(,)*) => {
$(
impl SolDecode for $ty {
type SolType = $ty;
fn from_sol_type(value: Self::SolType) -> Self {
value
}
}
)*
};
}
macro_rules! impl_primitive_encode {
($($ty: ty),+ $(,)*) => {
$(
impl<'a> SolEncode<'a> for $ty {
type SolType = &'a $ty;
fn to_sol_type(&'a self) -> Self::SolType {
self
}
}
)*
};
}
macro_rules! impl_primitive {
($($ty: ty),+ $(,)*) => {
$(
impl_primitive_decode!($ty);
impl_primitive_encode!($ty);
)*
};
}
impl_primitive! {
bool,
i8, i16, i32, i64, i128,
u8, u16, u32, u64, u128, U256,
String,
Box<str>,
Address,
}
impl<T: SolDecode, const N: usize> SolDecode for [T; N] {
type SolType = [T::SolType; N];
fn from_sol_type(value: Self::SolType) -> Self {
value.map(<T as SolDecode>::from_sol_type)
}
}
impl<'a, T: SolEncode<'a>, const N: usize> SolEncode<'a> for [T; N] {
type SolType = [T::SolType; N];
fn to_sol_type(&'a self) -> Self::SolType {
self.each_ref().map(<T as SolEncode>::to_sol_type)
}
}
impl<T: SolDecode> SolDecode for Vec<T> {
type SolType = Vec<T::SolType>;
fn from_sol_type(value: Self::SolType) -> Self {
value
.into_iter()
.map(<T as SolDecode>::from_sol_type)
.collect()
}
}
impl<'a, T: SolEncode<'a>> SolEncode<'a> for Vec<T> {
type SolType = Vec<T::SolType>;
fn to_sol_type(&'a self) -> Self::SolType {
self.iter().map(<T as SolEncode>::to_sol_type).collect()
}
}
impl<T: SolDecode> SolDecode for Box<[T]> {
type SolType = Box<[T::SolType]>;
fn from_sol_type(value: Self::SolType) -> Self {
Box::from_iter(
core::iter::IntoIterator::into_iter(value)
.map(<T as SolDecode>::from_sol_type),
)
}
}
impl<'a, T: SolEncode<'a>> SolEncode<'a> for Box<[T]> {
type SolType = Box<[T::SolType]>;
fn to_sol_type(&'a self) -> Self::SolType {
self.iter().map(<T as SolEncode>::to_sol_type).collect()
}
}
#[impl_for_tuples(12)]
impl SolDecode for Tuple {
for_tuples!( type SolType = ( #( Tuple::SolType ),* ); );
#[allow(clippy::unused_unit)]
fn from_sol_type(value: Self::SolType) -> Self {
for_tuples!( ( #( Tuple::from_sol_type(value.Tuple) ),* ) );
}
}
#[impl_for_tuples(12)]
impl<'a> SolEncode<'a> for Tuple {
for_tuples!( type SolType = ( #( Tuple::SolType ),* ); );
#[allow(clippy::unused_unit)]
fn to_sol_type(&'a self) -> Self::SolType {
for_tuples! ( ( #( self.Tuple.to_sol_type() ),* ) )
}
}
macro_rules! impl_refs_encode {
($([$($gen:tt)*] $ty: ty), +$(,)*) => {
$(
impl<$($gen)* T: SolEncode<'a>> SolEncode<'a> for $ty {
type SolType = T::SolType;
fn to_sol_type(&'a self) -> Self::SolType {
<T as SolEncode>::to_sol_type(self)
}
}
)*
};
}
impl_refs_encode! {
['a,] &'a T,
['a,] &'a mut T,
['a,] Box<T>,
}
impl<'a, T: SolEncode<'a> + Clone> SolEncode<'a> for Cow<'a, T> {
type SolType = T::SolType;
fn to_sol_type(&'a self) -> Self::SolType {
<T as SolEncode>::to_sol_type(self.deref())
}
}
macro_rules! impl_str_ref_encode {
($($ty: ty),+ $(,)*) => {
$(
impl<'a> SolEncode<'a> for $ty {
type SolType = &'a str;
fn to_sol_type(&'a self) -> Self::SolType {
self
}
}
)*
};
}
impl_str_ref_encode!(&'a str, &'a mut str);
macro_rules! impl_slice_ref_encode {
($($ty: ty),+ $(,)*) => {
$(
impl<'a, T: SolEncode<'a>> SolEncode<'a> for $ty {
type SolType = Vec<T::SolType>;
fn to_sol_type(&'a self) -> Self::SolType {
self.iter().map(<T as SolEncode>::to_sol_type).collect()
}
}
)*
};
}
impl_slice_ref_encode!(&'a [T], &'a mut [T]);
impl SolDecode for AccountId {
type SolType = SolBytes<[u8; 32]>;
fn from_sol_type(value: Self::SolType) -> Self {
AccountId(value.0)
}
}
impl SolEncode<'_> for AccountId {
type SolType = SolBytes<[u8; 32]>;
fn encode(&self) -> Vec<u8> {
sol_data::FixedBytes::abi_encode(self)
}
fn to_sol_type(&self) -> Self::SolType {
SolBytes(self.0)
}
}
impl SolDecode for Hash {
type SolType = SolBytes<[u8; 32]>;
fn from_sol_type(value: Self::SolType) -> Self {
Hash::from(value.0)
}
}
impl SolEncode<'_> for Hash {
type SolType = SolBytes<[u8; 32]>;
fn encode(&self) -> Vec<u8> {
sol_data::FixedBytes::abi_encode(self)
}
fn to_sol_type(&self) -> Self::SolType {
SolBytes::<[u8; 32]>((*self).into())
}
}
impl SolDecode for H256 {
type SolType = SolBytes<[u8; 32]>;
fn from_sol_type(value: Self::SolType) -> Self {
H256(value.0)
}
}
impl SolEncode<'_> for H256 {
type SolType = SolBytes<[u8; 32]>;
fn encode(&self) -> Vec<u8> {
sol_data::FixedBytes::abi_encode(&self.0)
}
fn to_sol_type(&self) -> Self::SolType {
SolBytes(self.0)
}
}