use alloy_sol_types::{
abi::token::{
PackedSeqToken,
WordToken,
},
sol_data,
SolType as AlloySolType,
};
use core::{
borrow::Borrow,
ops::Deref,
};
use ink_prelude::{
boxed::Box,
vec::Vec,
};
use scale::{
Decode,
Encode,
};
#[cfg(feature = "std")]
use scale_info::TypeInfo;
use crate::sol::{
SolDecode,
SolEncode,
SolTypeDecode,
SolTypeEncode,
};
#[derive(Debug, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(TypeInfo))]
pub struct SolBytes<T: SolBytesType>(pub T);
impl<T: SolBytesType> SolTypeDecode for SolBytes<T> {
type AlloyType = T::AlloyType;
fn detokenize(
token: <Self::AlloyType as AlloySolType>::Token<'_>,
) -> Result<Self, alloy_sol_types::Error> {
Ok(Self(<T as SolBytesType>::detokenize(token)))
}
}
impl<T: SolBytesType> SolTypeEncode for SolBytes<T> {
type AlloyType = T::AlloyType;
fn tokenize(&self) -> <Self::AlloyType as AlloySolType>::Token<'_> {
<T as SolBytesType>::tokenize(self)
}
}
impl<T: SolBytesType> crate::sol::types::private::Sealed for SolBytes<T> {}
impl<T: SolBytesType> SolDecode for SolBytes<T> {
type SolType = SolBytes<T>;
fn from_sol_type(value: Self::SolType) -> Self {
value
}
}
impl<'a, T: SolBytesType + 'a> SolEncode<'a> for SolBytes<T> {
type SolType = &'a SolBytes<T>;
fn to_sol_type(&'a self) -> Self::SolType {
self
}
}
impl<T: SolBytesType> Deref for SolBytes<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T: SolBytesType> Borrow<T> for SolBytes<T> {
fn borrow(&self) -> &T {
&self.0
}
}
impl<T: SolBytesType> AsRef<T> for SolBytes<T> {
fn as_ref(&self) -> &T {
&self.0
}
}
impl AsRef<[u8]> for SolBytes<Vec<u8>> {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
pub trait SolBytesType: private::Sealed {
type AlloyType: AlloySolType;
fn tokenize(&self) -> <Self::AlloyType as AlloySolType>::Token<'_>;
fn detokenize(token: <Self::AlloyType as AlloySolType>::Token<'_>) -> Self;
}
impl SolBytesType for u8
where
sol_data::ByteCount<1>: sol_data::SupportedFixedBytes,
{
type AlloyType = sol_data::FixedBytes<1>;
fn tokenize(&self) -> <Self::AlloyType as AlloySolType>::Token<'_> {
let mut word = [0; 32];
word[0] = *self;
WordToken::from(word)
}
fn detokenize(token: <Self::AlloyType as AlloySolType>::Token<'_>) -> Self {
token.0 .0[0]
}
}
impl private::Sealed for u8 {}
impl<const N: usize> SolBytesType for [u8; N]
where
sol_data::ByteCount<N>: sol_data::SupportedFixedBytes,
{
type AlloyType = sol_data::FixedBytes<N>;
fn tokenize(&self) -> <Self::AlloyType as AlloySolType>::Token<'_> {
let mut word = [0; 32];
word[..N].copy_from_slice(self.as_slice());
WordToken::from(word)
}
fn detokenize(token: <Self::AlloyType as AlloySolType>::Token<'_>) -> Self {
token.0 .0[..N]
.try_into()
.expect("Expected a slice of N bytes")
}
}
impl<const N: usize> private::Sealed for [u8; N] {}
impl SolBytesType for Vec<u8> {
type AlloyType = sol_data::Bytes;
fn tokenize(&self) -> <Self::AlloyType as AlloySolType>::Token<'_> {
PackedSeqToken(self.as_slice())
}
fn detokenize(token: <Self::AlloyType as AlloySolType>::Token<'_>) -> Self {
token.into_vec()
}
}
impl private::Sealed for Vec<u8> {}
impl SolBytesType for Box<[u8]> {
type AlloyType = sol_data::Bytes;
fn detokenize(token: <Self::AlloyType as AlloySolType>::Token<'_>) -> Self {
Box::from(token.0)
}
fn tokenize(&self) -> <Self::AlloyType as AlloySolType>::Token<'_> {
PackedSeqToken(self.as_ref())
}
}
impl private::Sealed for Box<[u8]> {}
mod private {
pub trait Sealed {}
}