everscale_types/abi/
mod.rs

1//! Common ABI implementation.
2
3use std::hash::{BuildHasher, Hash};
4use std::str::FromStr;
5
6pub use self::contract::{
7    Contract, Event, EventBuilder, ExternalInput, Function, FunctionBuilder, UnsignedBody,
8    UnsignedExternalMessage,
9};
10pub use self::signature::{extend_signature_with_id, sign_with_signature_id};
11pub use self::traits::{
12    FromAbi, FromAbiIter, FromPlainAbi, IgnoreName, IntoAbi, IntoPlainAbi, WithAbiType,
13    WithPlainAbiType,
14};
15pub use self::ty::{
16    AbiHeaderType, AbiType, AbiTypeFlatten, NamedAbiType, NamedAbiTypeFlatten, PlainAbiType,
17};
18pub use self::value::{AbiHeader, AbiValue, NamedAbiValue, PlainAbiValue};
19
20pub mod error;
21
22mod contract;
23mod signature;
24mod traits;
25mod ty;
26mod value;
27
28#[cfg(test)]
29mod tests;
30
31/// ABI version.
32#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
33pub struct AbiVersion {
34    /// Major version component.
35    pub major: u8,
36    /// Minor version component.
37    pub minor: u8,
38}
39
40impl AbiVersion {
41    /// A legacy ABI version.
42    pub const V1_0: Self = Self::new(1, 0);
43    /// A base version of an ABI 2.
44    pub const V2_0: Self = Self::new(2, 0);
45    /// A base version with strings and refs.
46    pub const V2_1: Self = Self::new(2, 1);
47    /// Same as 2.1 but with a more compact address serialization.
48    pub const V2_2: Self = Self::new(2, 2);
49    /// Same as 2.2 but uses an address during signing.
50    pub const V2_3: Self = Self::new(2, 3);
51
52    /// Creates an ABI version from components.
53    pub const fn new(major: u8, minor: u8) -> Self {
54        Self { major, minor }
55    }
56}
57
58impl FromStr for AbiVersion {
59    type Err = error::ParseAbiVersionError;
60
61    fn from_str(s: &str) -> Result<Self, Self::Err> {
62        let (major, minor) = ok!(s
63            .split_once('.')
64            .ok_or(error::ParseAbiVersionError::InvalidFormat));
65
66        Ok(Self {
67            major: ok!(major
68                .parse()
69                .map_err(error::ParseAbiVersionError::InvalidComponent)),
70            minor: ok!(minor
71                .parse()
72                .map_err(error::ParseAbiVersionError::InvalidComponent)),
73        })
74    }
75}
76
77impl std::fmt::Display for AbiVersion {
78    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
79        write!(f, "{}.{}", self.major, self.minor)
80    }
81}
82
83/// A wrapper around [`AbiType`], [`NamedAbiType`], [`AbiValue`] and [`NamedAbiValue`]
84/// that implements hash/comparison traits without name.
85#[repr(transparent)]
86pub struct WithoutName<T>(pub T);
87
88impl<T> WithoutName<T> {
89    /// Wraps a reference of the inner type.
90    pub fn wrap(value: &T) -> &Self {
91        // SAFETY: HashWithoutName<T> is #[repr(transparent)]
92        unsafe { &*(value as *const T as *const Self) }
93    }
94
95    /// Wraps a slice of the inner type.
96    pub fn wrap_slice(value: &[T]) -> &[Self] {
97        // SAFETY: HashWithoutName<T> is #[repr(transparent)]
98        unsafe { &*(value as *const [T] as *const [Self]) }
99    }
100}
101
102impl<T: std::fmt::Debug> std::fmt::Debug for WithoutName<T> {
103    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104        f.debug_tuple("WithoutName").field(&self.0).finish()
105    }
106}
107
108impl<T: Clone> Clone for WithoutName<T> {
109    #[inline]
110    fn clone(&self) -> Self {
111        WithoutName(self.0.clone())
112    }
113}
114
115impl<T> Eq for WithoutName<T> where WithoutName<T>: PartialEq {}
116
117impl<T> PartialOrd for WithoutName<T>
118where
119    WithoutName<T>: Ord,
120{
121    #[inline]
122    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
123        Some(self.cmp(other))
124    }
125}
126
127impl<T> PartialEq for WithoutName<Vec<T>>
128where
129    WithoutName<T>: PartialEq,
130{
131    fn eq(&self, WithoutName(other): &Self) -> bool {
132        WithoutName::wrap_slice(self.0.as_slice()) == WithoutName::wrap_slice(other.as_slice())
133    }
134}
135
136impl<K, V> PartialEq for WithoutName<std::collections::BTreeMap<K, V>>
137where
138    K: PartialEq,
139    WithoutName<V>: PartialEq,
140{
141    fn eq(&self, WithoutName(other): &Self) -> bool {
142        self.0.len() == other.len()
143            && self.0.iter().zip(other).all(|((ak, av), (bk, bv))| {
144                (ak, WithoutName::wrap(av)) == (bk, WithoutName::wrap(bv))
145            })
146    }
147}
148
149impl<K, V, S> PartialEq for WithoutName<std::collections::HashMap<K, V, S>>
150where
151    K: Eq + Hash,
152    WithoutName<V>: PartialEq,
153    S: BuildHasher,
154{
155    fn eq(&self, WithoutName(other): &Self) -> bool {
156        if self.0.len() != other.len() {
157            return false;
158        }
159
160        self.0.iter().all(|(key, value)| {
161            other
162                .get(key)
163                .map_or(false, |v| WithoutName::wrap(value) == WithoutName::wrap(v))
164        })
165    }
166}