Skip to content

Commit

Permalink
feat(abi): add [Named]AbiType::flatten
Browse files Browse the repository at this point in the history
  • Loading branch information
Rexagon committed Oct 28, 2024
1 parent 9ad9d01 commit 6a60b58
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 7 deletions.
4 changes: 3 additions & 1 deletion src/abi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
50 changes: 44 additions & 6 deletions src/abi/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ pub trait IgnoreName {
}

impl<T: IgnoreName> 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<'_> {
Expand All @@ -41,7 +44,10 @@ impl<T> IgnoreName for Vec<T>
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<'_> {
Expand All @@ -50,7 +56,10 @@ where
}

impl<T: IgnoreName> IgnoreName for Box<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<'_> {
Expand All @@ -59,7 +68,10 @@ impl<T: IgnoreName> IgnoreName for Box<T> {
}

impl<T: IgnoreName> IgnoreName for Arc<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<'_> {
Expand All @@ -68,7 +80,10 @@ impl<T: IgnoreName> IgnoreName for Arc<T> {
}

impl<T: IgnoreName> IgnoreName for Rc<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<'_> {
Expand All @@ -77,7 +92,10 @@ impl<T: IgnoreName> IgnoreName for Rc<T> {
}

impl<T: IgnoreName> IgnoreName for Option<T> {
type Unnamed<'a> = Option<T::Unnamed<'a>> where Self: 'a;
type Unnamed<'a>
= Option<T::Unnamed<'a>>
where
Self: 'a;

#[inline]
fn ignore_name(&self) -> Self::Unnamed<'_> {
Expand Down Expand Up @@ -928,6 +946,26 @@ impl FromAbi for HashBytes {
}
}

impl FromPlainAbi for HashBytes {
fn from_plain_abi(value: PlainAbiValue) -> Result<Self> {
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<Self> {
match value {
Expand Down
91 changes: 91 additions & 0 deletions src/abi/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<AbiType> for NamedAbiType {
Expand Down Expand Up @@ -178,6 +199,32 @@ impl std::borrow::Borrow<WithoutName<AbiType>> for WithoutName<NamedAbiType> {
}
}

/// An iterator that flattens the first-level tuple.
#[derive(Clone)]
pub enum NamedAbiTypeFlatten {
Single(Option<NamedAbiType>),
Tuple(Vec<NamedAbiType>),
}

impl Iterator for NamedAbiTypeFlatten {
type Item = NamedAbiType;

fn size_hint(&self) -> (usize, Option<usize>) {
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<Self::Item> {
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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -697,6 +762,32 @@ impl Hash for WithoutName<AbiType> {
}
}

/// An iterator that flattens the first-level tuple.
#[derive(Clone)]
pub enum AbiTypeFlatten {
Single(Option<AbiType>),
Tuple(Vec<NamedAbiType>),
}

impl Iterator for AbiTypeFlatten {
type Item = AbiType;

fn size_hint(&self) -> (usize, Option<usize>) {
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<Self::Item> {
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)]
Expand Down

0 comments on commit 6a60b58

Please sign in to comment.