tycho_types/abi/
mod.rs

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