Skip to content

Commit

Permalink
Add abi type
Browse files Browse the repository at this point in the history
  • Loading branch information
Rexagon committed Aug 31, 2023
1 parent 2452d93 commit 2fdd400
Show file tree
Hide file tree
Showing 8 changed files with 753 additions and 6 deletions.
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ members = ["proc"]
ahash = "0.8"
base64 = { version = "0.21.0", optional = true }
bitflags = "2.3"
bytes = { version = "1.4", optional = true }
crc32c = "0.6"
hex = "0.4"
once_cell = "1.16"
Expand All @@ -48,11 +49,12 @@ serde = { version = "1", features = ["derive"] }
serde_json = "1"

[features]
default = ["base64", "serde", "models", "sync"]
default = ["base64", "serde", "models", "abi", "sync"]
sync = []
stats = []
serde = ["dep:serde", "base64"]
models = ["dep:everscale-crypto", "dep:tl-proto"]
abi = ["dep:serde", "dep:bytes", "models"]
venom = []

[profile.release]
Expand Down
53 changes: 53 additions & 0 deletions src/abi/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//! ABI related error types.
/// Error type for ABI type parsing related errors.
#[derive(Debug, Clone, thiserror::Error)]
pub enum ParseAbiTypeError {
/// Error while parsing array type.
#[error("invalid array type")]
InvalidArrayType,
/// Error while parsing array length.
#[error("invalid array length")]
InvalidArrayLength(#[source] std::num::ParseIntError),
/// Error while parsing integer bit length.
#[error("invalid integer bit length")]
InvalidBitLen(#[source] std::num::ParseIntError),
/// Error while parsing varint or fixedbytes byte length.
#[error("invalid byte length")]
InvalidByteLen(#[source] std::num::ParseIntError),
/// Expected type to be terminated with ')'.
#[error("unterminated inner type")]
UnterminatedInnerType,
/// Expected value type for map.
#[error("map value type not found")]
ValueTypeNotFound,
/// Invalid ABI type.
#[error("unknown type")]
UnknownType,
}

/// Error type for named ABI type parsing related errors.
#[derive(Debug, Clone, thiserror::Error)]
pub enum ParseNamedAbiTypeError {
/// Error while parsing ABI type.
#[error("invalid type `{ty}`: {error}")]
InvalidType {
/// Parsed ABI type.
ty: String,
/// ABI type parsing error.
#[source]
error: ParseAbiTypeError,
},
/// Components array was not expected.
#[error("unexpected components for `{ty}`")]
UnexpectedComponents {
/// Parsed ABI type.
ty: String,
},
/// Expected components array for tuple.
#[error("expected components for `{ty}`")]
ExpectedComponents {
/// Parsed ABI type.
ty: String,
},
}
9 changes: 9 additions & 0 deletions src/abi/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//! Common ABI implementation.
pub use self::traits::{WithAbiType, WithPlainAbiType};
pub use self::ty::{AbiHeaderType, AbiType, NamedAbiType, PlainAbiType};

pub mod error;

mod traits;
mod ty;
172 changes: 172 additions & 0 deletions src/abi/traits.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
use std::collections::{BTreeMap, HashMap};
use std::num::NonZeroU8;

use bytes::Bytes;

use super::{AbiType, NamedAbiType, PlainAbiType};
use crate::cell::{Cell, HashBytes};
use crate::num::*;

use crate::models::message::{IntAddr, StdAddr, VarAddr};

/// A type with a known ABI type.
pub trait WithAbiType {
/// Returns a corresponding ABI type.
fn abi_type() -> AbiType;
}

macro_rules! impl_with_abi_type {
($($ty:ty => $ident:ident$(($n:expr))?),*$(,)?) => {$(
impl WithAbiType for $ty {
fn abi_type() -> AbiType {
AbiType::$ident$(($n))?
}
}
)*};
}

impl_with_abi_type! {
u8 => Uint(8),
u16 => Uint(16),
u32 => Uint(32),
u64 => Uint(64),
u128 => Uint(128),
HashBytes => Uint(256),
SplitDepth => Uint(5),
Uint9 => Uint(9),
Uint12 => Uint(12),
Uint15 => Uint(15),

i8 => Uint(8),
i16 => Uint(16),
i32 => Uint(32),
i64 => Uint(64),
i128 => Uint(128),

bool => Bool,

VarUint24 => VarUint(NonZeroU8::new(4).unwrap()),
VarUint56 => VarUint(NonZeroU8::new(8).unwrap()),
VarUint248 => VarUint(NonZeroU8::new(32).unwrap()),

Tokens => Token,

Cell => Cell,

Bytes => Bytes,
String => String,

IntAddr => Address,
StdAddr => Address,
VarAddr => Address,
}

impl<T: WithAbiType> WithAbiType for Option<T> {
fn abi_type() -> AbiType {
AbiType::Optional(Box::new(T::abi_type()))
}
}

impl<T: WithAbiType> WithAbiType for Vec<T> {
fn abi_type() -> AbiType {
AbiType::Array(Box::new(T::abi_type()))
}
}

impl<T: WithAbiType> WithAbiType for [T] {
fn abi_type() -> AbiType {
AbiType::Array(Box::new(T::abi_type()))
}
}

impl<T: WithAbiType, const N: usize> WithAbiType for [T; N] {
fn abi_type() -> AbiType {
AbiType::FixedArray(Box::new(T::abi_type()), N)
}
}

impl<K: WithPlainAbiType, V: WithAbiType> WithAbiType for BTreeMap<K, V> {
fn abi_type() -> AbiType {
AbiType::Map(K::plain_abi_type(), Box::new(V::abi_type()))
}
}

impl<K: WithPlainAbiType, V: WithAbiType, S> WithAbiType for HashMap<K, V, S> {
fn abi_type() -> AbiType {
AbiType::Map(K::plain_abi_type(), Box::new(V::abi_type()))
}
}

#[cfg(feature = "models")]
impl<T: WithAbiType> WithAbiType for crate::models::Lazy<T> {
fn abi_type() -> AbiType {
AbiType::Ref(Box::new(T::abi_type()))
}
}

impl WithAbiType for () {
fn abi_type() -> AbiType {
AbiType::Tuple(Vec::new())
}
}

macro_rules! impl_with_abi_type_for_tuple {
($($i:literal: $t:ident),+$(,)?) => {
impl<$($t: WithAbiType),*> WithAbiType for ($($t),+,) {
fn abi_type() -> AbiType {
AbiType::Tuple(vec![
$(NamedAbiType::from_index($i, <$t as WithAbiType>::abi_type())),*
])
}
}
};
}

impl_with_abi_type_for_tuple! { 0: T0 }
impl_with_abi_type_for_tuple! { 0: T0, 1: T1 }
impl_with_abi_type_for_tuple! { 0: T0, 1: T1, 2: T2 }
impl_with_abi_type_for_tuple! { 0: T0, 1: T1, 2: T2, 3: T3 }
impl_with_abi_type_for_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4 }
impl_with_abi_type_for_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5 }
impl_with_abi_type_for_tuple! { 0: T0, 1: T1, 2: T2, 3: T3, 4: T4, 5: T5, 6: T6 }

/// A type with a known plain ABI type.
pub trait WithPlainAbiType: WithAbiType {
/// Returns a corresponding plain ABI type.
fn plain_abi_type() -> PlainAbiType;
}

macro_rules! impl_with_plain_abi_type {
($($int:ty => $ident:ident$(($n:literal))?),*$(,)?) => {$(
impl WithPlainAbiType for $int {
fn plain_abi_type() -> PlainAbiType {
PlainAbiType::$ident$(($n))?
}
}
)*};
}

impl_with_plain_abi_type! {
u8 => Uint(8),
u16 => Uint(16),
u32 => Uint(32),
u64 => Uint(64),
u128 => Uint(128),
HashBytes => Uint(256),
SplitDepth => Uint(5),
Uint9 => Uint(9),
Uint12 => Uint(12),
Uint15 => Uint(15),

i8 => Uint(8),
i16 => Uint(16),
i32 => Uint(32),
i64 => Uint(64),
i128 => Uint(128),

bool => Bool,

IntAddr => Address,
StdAddr => Address,
VarAddr => Address,
}
Loading

0 comments on commit 2fdd400

Please sign in to comment.