diff --git a/src/abi/mod.rs b/src/abi/mod.rs index 602c2503..95ebaa48 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -12,7 +12,9 @@ pub use self::traits::{ FromAbi, FromAbiIter, FromPlainAbi, IgnoreName, IntoAbi, IntoPlainAbi, WithAbiType, WithPlainAbiType, }; -pub use self::ty::{AbiHeaderType, AbiType, NamedAbiType, PlainAbiType}; +pub use self::ty::{ + AbiHeaderType, AbiType, AbiTypeFlatten, NamedAbiType, NamedAbiTypeFlatten, PlainAbiType, +}; pub use self::value::{AbiHeader, AbiValue, NamedAbiValue, PlainAbiValue}; pub mod error; diff --git a/src/abi/traits.rs b/src/abi/traits.rs index e918d55b..51285afb 100644 --- a/src/abi/traits.rs +++ b/src/abi/traits.rs @@ -29,7 +29,10 @@ pub trait IgnoreName { } impl IgnoreName for &'_ T { - type Unnamed<'a> = T::Unnamed<'a> where Self: 'a; + type Unnamed<'a> + = T::Unnamed<'a> + where + Self: 'a; #[inline] fn ignore_name(&self) -> Self::Unnamed<'_> { @@ -41,7 +44,10 @@ impl IgnoreName for Vec where [T]: IgnoreName, { - type Unnamed<'a> = <[T] as IgnoreName>::Unnamed<'a> where Self: 'a; + type Unnamed<'a> + = <[T] as IgnoreName>::Unnamed<'a> + where + Self: 'a; #[inline] fn ignore_name(&self) -> Self::Unnamed<'_> { @@ -50,7 +56,10 @@ where } impl IgnoreName for Box { - type Unnamed<'a> = T::Unnamed<'a> where Self: 'a; + type Unnamed<'a> + = T::Unnamed<'a> + where + Self: 'a; #[inline] fn ignore_name(&self) -> Self::Unnamed<'_> { @@ -59,7 +68,10 @@ impl IgnoreName for Box { } impl IgnoreName for Arc { - type Unnamed<'a> = T::Unnamed<'a> where Self: 'a; + type Unnamed<'a> + = T::Unnamed<'a> + where + Self: 'a; #[inline] fn ignore_name(&self) -> Self::Unnamed<'_> { @@ -68,7 +80,10 @@ impl IgnoreName for Arc { } impl IgnoreName for Rc { - type Unnamed<'a> = T::Unnamed<'a> where Self: 'a; + type Unnamed<'a> + = T::Unnamed<'a> + where + Self: 'a; #[inline] fn ignore_name(&self) -> Self::Unnamed<'_> { @@ -77,7 +92,10 @@ impl IgnoreName for Rc { } impl IgnoreName for Option { - type Unnamed<'a> = Option> where Self: 'a; + type Unnamed<'a> + = Option> + where + Self: 'a; #[inline] fn ignore_name(&self) -> Self::Unnamed<'_> { @@ -928,6 +946,26 @@ impl FromAbi for HashBytes { } } +impl FromPlainAbi for HashBytes { + fn from_plain_abi(value: PlainAbiValue) -> Result { + match &value { + PlainAbiValue::Uint(256, v) => { + let mut result = HashBytes::ZERO; + + let bytes = v.to_bytes_be(); + let bytes_len = bytes.len(); + match 32usize.checked_sub(bytes_len) { + None => result.0.copy_from_slice(&bytes[bytes_len - 32..]), + Some(pad) => result.0[pad..].copy_from_slice(&bytes), + }; + + Ok(result) + } + value => Err(expected_plain_type("uint256", value)), + } + } +} + impl FromAbi for Cell { fn from_abi(value: AbiValue) -> Result { match value { diff --git a/src/abi/ty.rs b/src/abi/ty.rs index 8ddf113b..cf50bdec 100644 --- a/src/abi/ty.rs +++ b/src/abi/ty.rs @@ -38,6 +38,27 @@ impl NamedAbiType { pub fn from_index(index: usize, ty: AbiType) -> Self { Self::new(format!("value{index}"), ty) } + + /// Returns an iterator with the first-level tuple flattened. + /// + /// Can be used to pass an ABI struct as arguments to the + /// [`FunctionBuilder::with_inputs`] or [`FunctionBuilder::with_outputs`]. + /// + /// [`FunctionBuilder::with_inputs`]: fn@crate::abi::FunctionBuilder::with_inputs + /// [`FunctionBuilder::with_outputs`]: fn@crate::abi::FunctionBuilder::with_outputs + pub fn flatten(self) -> NamedAbiTypeFlatten { + match self.ty { + AbiType::Tuple(tuple) => { + let mut items = tuple.to_vec(); + items.reverse(); + NamedAbiTypeFlatten::Tuple(items) + } + ty => NamedAbiTypeFlatten::Single(Some(NamedAbiType { + name: self.name, + ty, + })), + } + } } impl AsRef for NamedAbiType { @@ -178,6 +199,32 @@ impl std::borrow::Borrow> for WithoutName { } } +/// An iterator that flattens the first-level tuple. +#[derive(Clone)] +pub enum NamedAbiTypeFlatten { + Single(Option), + Tuple(Vec), +} + +impl Iterator for NamedAbiTypeFlatten { + type Item = NamedAbiType; + + fn size_hint(&self) -> (usize, Option) { + let size = match self { + Self::Single(item) => item.is_some() as usize, + Self::Tuple(items) => items.len(), + }; + (size, Some(size)) + } + + fn next(&mut self) -> Option { + match self { + Self::Single(item) => item.take(), + Self::Tuple(items) => items.pop(), + } + } +} + /// Contract header value type. #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] pub enum AbiHeaderType { @@ -396,6 +443,24 @@ impl AbiType { } } + /// Returns an iterator with the first-level tuple flattened. + /// + /// Can be used to pass an ABI struct as arguments to the + /// [`FunctionBuilder::with_unnamed_inputs`] or [`FunctionBuilder::with_unnamed_outputs`] + /// + /// [`FunctionBuilder::with_unnamed_inputs`]: fn@crate::abi::FunctionBuilder::with_unnamed_inputs + /// [`FunctionBuilder::with_unnamed_outputs`]: fn@crate::abi::FunctionBuilder::with_unnamed_outputs + pub fn flatten(self) -> AbiTypeFlatten { + match self { + AbiType::Tuple(tuple) => { + let mut items = tuple.to_vec(); + items.reverse(); + AbiTypeFlatten::Tuple(items) + } + ty => AbiTypeFlatten::Single(Some(ty)), + } + } + /// Simple `varuintN` type constructor. #[inline] pub fn varuint(size: u8) -> Self { @@ -697,6 +762,32 @@ impl Hash for WithoutName { } } +/// An iterator that flattens the first-level tuple. +#[derive(Clone)] +pub enum AbiTypeFlatten { + Single(Option), + Tuple(Vec), +} + +impl Iterator for AbiTypeFlatten { + type Item = AbiType; + + fn size_hint(&self) -> (usize, Option) { + let size = match self { + Self::Single(item) => item.is_some() as usize, + Self::Tuple(items) => items.len(), + }; + (size, Some(size)) + } + + fn next(&mut self) -> Option { + match self { + Self::Single(item) => item.take(), + Self::Tuple(items) => items.pop().map(|item| item.ty), + } + } +} + /// ABI type which has a fixed bits representation /// and therefore can be used as a map key. #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]