Skip to content

Commit

Permalink
Improve abi value type check
Browse files Browse the repository at this point in the history
  • Loading branch information
Rexagon committed Sep 5, 2023
1 parent 2b19f8e commit 8205988
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 2 deletions.
4 changes: 2 additions & 2 deletions src/abi/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ use anyhow::Result;
use sha2::Digest;

use crate::abi::AbiValue;
use crate::prelude::CellSlice;
use crate::cell::{CellBuilder, CellSlice};

Check warning on line 6 in src/abi/contract.rs

View workflow job for this annotation

GitHub Actions / Check

unused import: `CellBuilder`

Check failure on line 6 in src/abi/contract.rs

View workflow job for this annotation

GitHub Actions / Lints

unused import: `CellBuilder`

Check warning on line 6 in src/abi/contract.rs

View workflow job for this annotation

GitHub Actions / Test Suite

unused import: `CellBuilder`

use super::error::AbiError;
use super::{AbiHeaderType, AbiVersion, NamedAbiType, NamedAbiValue};
use crate::abi::error::AbiError;

pub struct Contract {

Check warning on line 11 in src/abi/contract.rs

View workflow job for this annotation

GitHub Actions / Check

struct `Contract` is never constructed

Check failure on line 11 in src/abi/contract.rs

View workflow job for this annotation

GitHub Actions / Lints

struct `Contract` is never constructed

Check warning on line 11 in src/abi/contract.rs

View workflow job for this annotation

GitHub Actions / Test Suite

struct `Contract` is never constructed
pub abi_version: AbiVersion,
Expand Down
91 changes: 91 additions & 0 deletions src/abi/value/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ use std::collections::BTreeMap;
use std::num::NonZeroU8;
use std::sync::Arc;

use anyhow::Result;
use bytes::Bytes;
use everscale_crypto::ed25519;
use num_bigint::{BigInt, BigUint};

use super::{ty::*, IntoAbi, IntoPlainAbi, WithAbiType, WithPlainAbiType};
use crate::abi::error::AbiError;
use crate::cell::Cell;
use crate::models::IntAddr;
use crate::num::Tokens;
Expand All @@ -24,6 +26,18 @@ pub struct NamedAbiValue {
}

impl NamedAbiValue {
/// Ensures that all values satisfy the provided types.
pub fn check_types(items: &[Self], types: &[NamedAbiType]) -> Result<()> {
anyhow::ensure!(
Self::have_types(items, types),
AbiError::TypeMismatch {
expected: format!("{}", DisplayTupleType(types)).into(),
ty: format!("{}", DisplayTupleValueType(items)).into(),
}
);
Ok(())
}

/// Returns whether all values satisfy the provided types.
pub fn have_types(items: &[Self], types: &[NamedAbiType]) -> bool {
items.len() == types.len()
Expand Down Expand Up @@ -173,6 +187,12 @@ impl AbiValue {
}
}

/// Returns a printable object which will display a value type signature.
#[inline]
pub fn display_type(&self) -> impl std::fmt::Display + '_ {
DisplayValueType(self)
}

/// Simple `uintN` constructor.
#[inline]
pub fn uint<T>(bits: u16, value: T) -> Self
Expand Down Expand Up @@ -388,3 +408,74 @@ impl AbiHeader {
)
}
}

struct DisplayValueType<'a>(&'a AbiValue);

impl std::fmt::Display for DisplayValueType<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match &self.0 {
AbiValue::Uint(n, _) => return write!(f, "uint{n}"),
AbiValue::Int(n, _) => return write!(f, "int{n}"),
AbiValue::VarUint(n, _) => return write!(f, "varuint{n}"),
AbiValue::VarInt(n, _) => return write!(f, "varint{n}"),
AbiValue::Bool(_) => "bool",
AbiValue::Cell(_) => "cell",
AbiValue::Address(_) => "address",
AbiValue::Bytes(_) => "bytes",
AbiValue::FixedBytes(bytes) => return write!(f, "fixedbytes{}", bytes.len()),
AbiValue::String(_) => "string",
AbiValue::Token(_) => "gram",
AbiValue::Tuple(items) => {
return std::fmt::Display::fmt(&DisplayTupleValueType(items), f)
}
AbiValue::Array(ty, _) => return write!(f, "{ty}[]"),
AbiValue::FixedArray(ty, items) => return write!(f, "{ty}[{}]", items.len()),
AbiValue::Map(key_ty, value_ty, _) => return write!(f, "map({key_ty},{value_ty})"),
AbiValue::Optional(ty, _) => return write!(f, "optional({ty})"),
AbiValue::Ref(val) => return write!(f, "ref({})", val.display_type()),
};
f.write_str(s)
}
}

struct DisplayTupleValueType<'a>(&'a [NamedAbiValue]);

impl std::fmt::Display for DisplayTupleValueType<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = if self.0.is_empty() {
"()"
} else {
let mut first = true;
ok!(f.write_str("("));
for item in self.0 {
if !std::mem::take(&mut first) {
ok!(f.write_str(","));
}
ok!(write!(f, "{}", item.value.display_type()));
}
")"
};
f.write_str(s)
}
}

struct DisplayTupleType<'a>(&'a [NamedAbiType]);

impl std::fmt::Display for DisplayTupleType<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = if self.0.is_empty() {
"()"
} else {
let mut first = true;
ok!(f.write_str("("));
for item in self.0 {
if !std::mem::take(&mut first) {
ok!(f.write_str(","));
}
ok!(write!(f, "{}", item.ty));
}
")"
};
f.write_str(s)
}
}

0 comments on commit 8205988

Please sign in to comment.