Skip to main content

tycho_types/abi/value/
mod.rs

1use std::collections::BTreeMap;
2use std::num::NonZeroU8;
3use std::sync::Arc;
4
5use anyhow::Result;
6use bytes::Bytes;
7use num_bigint::{BigInt, BigUint};
8
9use super::ty::*;
10use super::{IntoAbi, IntoPlainAbi, WithAbiType, WithPlainAbiType, WithoutName};
11use crate::abi::error::AbiError;
12use crate::cell::{Cell, CellFamily};
13use crate::models::{AnyAddr, IntAddr, StdAddr};
14use crate::num::Tokens;
15
16mod de;
17pub(crate) mod ser;
18
19/// ABI value with name.
20#[derive(Debug, Clone, Eq, PartialEq)]
21pub struct NamedAbiValue {
22    /// Item name.
23    pub name: Arc<str>,
24    /// ABI value.
25    pub value: AbiValue,
26}
27
28impl NamedAbiValue {
29    /// Ensures that all values satisfy the provided types.
30    pub fn check_types(items: &[Self], types: &[NamedAbiType]) -> Result<()> {
31        anyhow::ensure!(Self::have_types(items, types), AbiError::TypeMismatch {
32            expected: DisplayTupleType(types).to_string().into(),
33            ty: DisplayTupleValueType(items).to_string().into(),
34        });
35        Ok(())
36    }
37
38    /// Returns whether all values satisfy the provided types.
39    pub fn have_types(items: &[Self], types: &[NamedAbiType]) -> bool {
40        items.len() == types.len()
41            && items
42                .iter()
43                .zip(types.iter())
44                .all(|(item, t)| item.value.has_type(&t.ty))
45    }
46
47    /// Creates a named ABI value with an index name (e.g. `value123`).
48    pub fn from_index(index: usize, value: AbiValue) -> Self {
49        Self {
50            name: format!("value{index}").into(),
51            value,
52        }
53    }
54
55    /// Ensures that value satisfies the type.
56    pub fn check_type<T: AsRef<AbiType>>(&self, ty: T) -> Result<()> {
57        fn type_mismatch(this: &NamedAbiValue, expected: &AbiType) -> AbiError {
58            AbiError::TypeMismatch {
59                expected: expected.to_string().into(),
60                ty: this.value.display_type().to_string().into(),
61            }
62        }
63        let ty = ty.as_ref();
64        anyhow::ensure!(self.value.has_type(ty), type_mismatch(self, ty));
65        Ok(())
66    }
67}
68
69impl From<(String, AbiValue)> for NamedAbiValue {
70    #[inline]
71    fn from((name, value): (String, AbiValue)) -> Self {
72        Self {
73            name: name.into(),
74            value,
75        }
76    }
77}
78
79impl<'a> From<(&'a str, AbiValue)> for NamedAbiValue {
80    #[inline]
81    fn from((name, value): (&'a str, AbiValue)) -> Self {
82        Self {
83            name: Arc::from(name),
84            value,
85        }
86    }
87}
88
89impl From<(usize, AbiValue)> for NamedAbiValue {
90    #[inline]
91    fn from((index, value): (usize, AbiValue)) -> Self {
92        Self::from_index(index, value)
93    }
94}
95
96impl NamedAbiType {
97    /// Returns a default value corresponding to the this type.
98    pub fn make_default_value(&self) -> NamedAbiValue {
99        NamedAbiValue {
100            name: self.name.clone(),
101            value: self.ty.make_default_value(),
102        }
103    }
104}
105
106impl PartialEq for WithoutName<NamedAbiValue> {
107    #[inline]
108    fn eq(&self, other: &Self) -> bool {
109        WithoutName::wrap(&self.0.value).eq(WithoutName::wrap(&other.0.value))
110    }
111}
112
113impl std::borrow::Borrow<WithoutName<AbiValue>> for WithoutName<NamedAbiValue> {
114    fn borrow(&self) -> &WithoutName<AbiValue> {
115        WithoutName::wrap(&self.0.value)
116    }
117}
118
119/// ABI encoded value.
120#[derive(Debug, Clone, Eq, PartialEq)]
121pub enum AbiValue {
122    /// Unsigned integer of n bits.
123    Uint(u16, BigUint),
124    /// Signed integer of n bits.
125    Int(u16, BigInt),
126    /// Variable-length unsigned integer of maximum n bytes.
127    VarUint(NonZeroU8, BigUint),
128    /// Variable-length signed integer of maximum n bytes.
129    VarInt(NonZeroU8, BigInt),
130    /// Boolean.
131    Bool(bool),
132    /// Tree of cells ([`Cell`]).
133    ///
134    /// [`Cell`]: crate::cell::Cell
135    Cell(Cell),
136    /// Any address ([`AnyAddr`]).
137    ///
138    /// [`AnyAddr`]: crate::models::message::AnyAddr
139    Address(Box<AnyAddr>),
140    /// Standard internal address ([`StdAddr`])
141    /// [`StdAddr`]: crate::models::message::StdAddr
142    AddressStd(Option<Box<StdAddr>>),
143    /// Byte array.
144    Bytes(Bytes),
145    /// Byte array of fixed length.
146    FixedBytes(Bytes),
147    /// Utf8-encoded string.
148    String(String),
149    /// Variable length 120-bit integer ([`Tokens`]).
150    ///
151    /// [`Tokens`]: crate::num::Tokens
152    Token(Tokens),
153    /// Product type.
154    Tuple(Vec<NamedAbiValue>),
155    /// Array of ABI values.
156    Array(Arc<AbiType>, Vec<Self>),
157    /// Fixed-length array of ABI values.
158    FixedArray(Arc<AbiType>, Vec<Self>),
159    /// Sorted dictionary of ABI values.
160    Map(
161        PlainAbiType,
162        Arc<AbiType>,
163        BTreeMap<PlainAbiValue, AbiValue>,
164    ),
165    /// Optional value.
166    Optional(Arc<AbiType>, Option<Box<Self>>),
167    /// Value stored in a new cell.
168    Ref(Box<Self>),
169}
170
171impl AbiValue {
172    /// Returns a named ABI value.
173    pub fn named<T: Into<String>>(self, name: T) -> NamedAbiValue {
174        NamedAbiValue {
175            name: Arc::from(name.into()),
176            value: self,
177        }
178    }
179
180    /// Ensures that value satisfies the type.
181    pub fn check_type<T: AsRef<AbiType>>(&self, ty: T) -> Result<()> {
182        fn type_mismatch(value: &AbiValue, expected: &AbiType) -> AbiError {
183            AbiError::TypeMismatch {
184                expected: expected.to_string().into(),
185                ty: value.display_type().to_string().into(),
186            }
187        }
188        let ty = ty.as_ref();
189        anyhow::ensure!(self.has_type(ty), type_mismatch(self, ty));
190        Ok(())
191    }
192
193    /// Returns whether this value has the same type as the provided one.
194    pub fn has_type(&self, ty: &AbiType) -> bool {
195        match (self, ty) {
196            (Self::Uint(n, _), AbiType::Uint(t)) => n == t,
197            (Self::Int(n, _), AbiType::Int(t)) => n == t,
198            (Self::VarUint(n, _), AbiType::VarUint(t)) => n == t,
199            (Self::VarInt(n, _), AbiType::VarInt(t)) => n == t,
200            (Self::FixedBytes(bytes), AbiType::FixedBytes(len)) => bytes.len() == *len,
201            (Self::Tuple(items), AbiType::Tuple(types)) => NamedAbiValue::have_types(items, types),
202            (Self::Array(ty, _), AbiType::Array(t)) => ty == t,
203            (Self::FixedArray(ty, items), AbiType::FixedArray(t, len)) => {
204                items.len() == *len && ty == t
205            }
206            (Self::Map(key_ty, value_ty, _), AbiType::Map(k, v)) => key_ty == k && value_ty == v,
207            (Self::Optional(ty, _), AbiType::Optional(t)) => ty == t,
208            (Self::Ref(value), AbiType::Ref(t)) => value.has_type(t),
209            (Self::Bool(_), AbiType::Bool)
210            | (Self::Cell(_), AbiType::Cell)
211            | (Self::Address(_), AbiType::Address)
212            | (Self::AddressStd(_), AbiType::AddressStd)
213            | (Self::Bytes(_), AbiType::Bytes)
214            | (Self::String(_), AbiType::String)
215            | (Self::Token(_), AbiType::Token) => true,
216            _ => false,
217        }
218    }
219
220    /// Returns an ABI type of the value.
221    pub fn get_type(&self) -> AbiType {
222        match self {
223            AbiValue::Uint(n, _) => AbiType::Uint(*n),
224            AbiValue::Int(n, _) => AbiType::Int(*n),
225            AbiValue::VarUint(n, _) => AbiType::VarUint(*n),
226            AbiValue::VarInt(n, _) => AbiType::VarInt(*n),
227            AbiValue::Bool(_) => AbiType::Bool,
228            AbiValue::Cell(_) => AbiType::Cell,
229            AbiValue::Address(_) => AbiType::Address,
230            AbiValue::AddressStd(_) => AbiType::AddressStd,
231            AbiValue::Bytes(_) => AbiType::Bytes,
232            AbiValue::FixedBytes(bytes) => AbiType::FixedBytes(bytes.len()),
233            AbiValue::String(_) => AbiType::String,
234            AbiValue::Token(_) => AbiType::Token,
235            AbiValue::Tuple(items) => AbiType::Tuple(
236                items
237                    .iter()
238                    .map(|item| NamedAbiType::new(item.name.clone(), item.value.get_type()))
239                    .collect(),
240            ),
241            AbiValue::Array(ty, _) => AbiType::Array(ty.clone()),
242            AbiValue::FixedArray(ty, items) => AbiType::FixedArray(ty.clone(), items.len()),
243            AbiValue::Map(key_ty, value_ty, _) => AbiType::Map(*key_ty, value_ty.clone()),
244            AbiValue::Optional(ty, _) => AbiType::Optional(ty.clone()),
245            AbiValue::Ref(value) => AbiType::Ref(Arc::new(value.get_type())),
246        }
247    }
248
249    /// Returns a printable object which will display a value type signature.
250    #[inline]
251    pub fn display_type(&self) -> impl std::fmt::Display + '_ {
252        DisplayValueType(self)
253    }
254
255    /// Simple `uintN` constructor.
256    #[inline]
257    pub fn uint<T>(bits: u16, value: T) -> Self
258    where
259        BigUint: From<T>,
260    {
261        Self::Uint(bits, BigUint::from(value))
262    }
263
264    /// Simple `intN` constructor.
265    #[inline]
266    pub fn int<T>(bits: u16, value: T) -> Self
267    where
268        BigInt: From<T>,
269    {
270        Self::Int(bits, BigInt::from(value))
271    }
272
273    /// Simple `varuintN` constructor.
274    #[inline]
275    pub fn varuint<T>(size: u8, value: T) -> Self
276    where
277        BigUint: From<T>,
278    {
279        Self::VarUint(NonZeroU8::new(size).unwrap(), BigUint::from(value))
280    }
281
282    /// Simple `varintN` constructor.
283    #[inline]
284    pub fn varint<T>(size: u8, value: T) -> Self
285    where
286        BigInt: From<T>,
287    {
288        Self::VarInt(NonZeroU8::new(size).unwrap(), BigInt::from(value))
289    }
290
291    /// Simple `address` constructor.
292    #[inline]
293    pub fn address<T>(value: T) -> Self
294    where
295        AnyAddr: From<T>,
296    {
297        Self::Address(Box::new(AnyAddr::from(value)))
298    }
299
300    /// Simple `address_std` constructor.
301    #[inline]
302    pub fn address_std<T>(value: T) -> Self
303    where
304        StdAddr: From<T>,
305    {
306        // TODO: Use `castaway` to specialize on `Box<StdAddr>`.
307        Self::AddressStd(Some(Box::new(StdAddr::from(value))))
308    }
309
310    /// Simple `bytes` constructor.
311    #[inline]
312    pub fn bytes<T>(value: T) -> Self
313    where
314        Bytes: From<T>,
315    {
316        Self::Bytes(Bytes::from(value))
317    }
318
319    /// Simple `bytes` constructor.
320    #[inline]
321    pub fn fixedbytes<T>(value: T) -> Self
322    where
323        Bytes: From<T>,
324    {
325        Self::FixedBytes(Bytes::from(value))
326    }
327
328    /// Simple `tuple` constructor.
329    #[inline]
330    pub fn tuple<I, T>(values: I) -> Self
331    where
332        I: IntoIterator<Item = T>,
333        NamedAbiValue: From<T>,
334    {
335        Self::Tuple(values.into_iter().map(NamedAbiValue::from).collect())
336    }
337
338    /// Simple `tuple` constructor.
339    #[inline]
340    pub fn unnamed_tuple<I>(values: I) -> Self
341    where
342        I: IntoIterator<Item = AbiValue>,
343    {
344        Self::Tuple(
345            values
346                .into_iter()
347                .enumerate()
348                .map(|(i, value)| NamedAbiValue::from_index(i, value))
349                .collect(),
350        )
351    }
352
353    /// Simple `array` constructor.
354    #[inline]
355    pub fn array<T, I>(values: I) -> Self
356    where
357        T: WithAbiType + IntoAbi,
358        I: IntoIterator<Item = T>,
359    {
360        Self::Array(
361            Arc::new(T::abi_type()),
362            values.into_iter().map(IntoAbi::into_abi).collect(),
363        )
364    }
365
366    /// Simple `fixedarray` constructor.
367    #[inline]
368    pub fn fixedarray<T, I>(values: I) -> Self
369    where
370        T: WithAbiType + IntoAbi,
371        I: IntoIterator<Item = T>,
372    {
373        Self::FixedArray(
374            Arc::new(T::abi_type()),
375            values.into_iter().map(IntoAbi::into_abi).collect(),
376        )
377    }
378
379    /// Simple `map` constructor.
380    #[inline]
381    pub fn map<K, V, I>(entries: I) -> Self
382    where
383        K: WithPlainAbiType + IntoPlainAbi,
384        V: WithAbiType + IntoAbi,
385        I: IntoIterator<Item = (K, V)>,
386    {
387        Self::Map(
388            K::plain_abi_type(),
389            Arc::new(V::abi_type()),
390            entries
391                .into_iter()
392                .map(|(key, value)| (key.into_plain_abi(), value.into_abi()))
393                .collect(),
394        )
395    }
396
397    /// Simple `optional` constructor.
398    #[inline]
399    pub fn optional<T>(value: Option<T>) -> Self
400    where
401        T: WithAbiType + IntoAbi,
402    {
403        Self::Optional(
404            Arc::new(T::abi_type()),
405            value.map(T::into_abi).map(Box::new),
406        )
407    }
408
409    /// Simple `optional` constructor.
410    #[inline]
411    pub fn reference<T>(value: T) -> Self
412    where
413        T: IntoAbi,
414    {
415        Self::Ref(Box::new(value.into_abi()))
416    }
417}
418
419impl AbiType {
420    /// Returns a default value corresponding to the this type.
421    pub fn make_default_value(&self) -> AbiValue {
422        match self {
423            AbiType::Uint(bits) => AbiValue::Uint(*bits, BigUint::default()),
424            AbiType::Int(bits) => AbiValue::Int(*bits, BigInt::default()),
425            AbiType::VarUint(size) => AbiValue::VarUint(*size, BigUint::default()),
426            AbiType::VarInt(size) => AbiValue::VarInt(*size, BigInt::default()),
427            AbiType::Bool => AbiValue::Bool(false),
428            AbiType::Cell => AbiValue::Cell(Cell::empty_cell()),
429            AbiType::Address => AbiValue::Address(Box::default()),
430            AbiType::AddressStd => AbiValue::AddressStd(None),
431            AbiType::Bytes => AbiValue::Bytes(Bytes::default()),
432            AbiType::FixedBytes(len) => AbiValue::FixedBytes(Bytes::from(vec![0u8; *len])),
433            AbiType::String => AbiValue::String(String::default()),
434            AbiType::Token => AbiValue::Token(Tokens::ZERO),
435            AbiType::Tuple(items) => {
436                let mut tuple = Vec::with_capacity(items.len());
437                for item in items.as_ref() {
438                    tuple.push(item.make_default_value());
439                }
440                AbiValue::Tuple(tuple)
441            }
442            AbiType::Array(ty) => AbiValue::Array(ty.clone(), Vec::new()),
443            AbiType::FixedArray(ty, items) => {
444                AbiValue::FixedArray(ty.clone(), vec![ty.make_default_value(); *items])
445            }
446            AbiType::Map(key_ty, value_ty) => {
447                AbiValue::Map(*key_ty, value_ty.clone(), BTreeMap::default())
448            }
449            AbiType::Optional(ty) => AbiValue::Optional(ty.clone(), None),
450            AbiType::Ref(ty) => AbiValue::Ref(Box::new(ty.make_default_value())),
451        }
452    }
453}
454
455impl PartialEq for WithoutName<AbiValue> {
456    fn eq(&self, other: &Self) -> bool {
457        match (&self.0, &other.0) {
458            (AbiValue::Uint(an, a), AbiValue::Uint(bn, b)) => an.eq(bn) && a.eq(b),
459            (AbiValue::Int(an, a), AbiValue::Int(bn, b)) => an.eq(bn) && a.eq(b),
460            (AbiValue::VarUint(an, a), AbiValue::VarUint(bn, b)) => an.eq(bn) && a.eq(b),
461            (AbiValue::VarInt(an, a), AbiValue::VarInt(bn, b)) => an.eq(bn) && a.eq(b),
462            (AbiValue::Bool(a), AbiValue::Bool(b)) => a.eq(b),
463            (AbiValue::Cell(a), AbiValue::Cell(b)) => a.eq(b),
464            (AbiValue::Address(a), AbiValue::Address(b)) => a.eq(b),
465            (AbiValue::AddressStd(a), AbiValue::AddressStd(b)) => a.eq(b),
466            (AbiValue::Bytes(a), AbiValue::Bytes(b)) => a.eq(b),
467            (AbiValue::FixedBytes(a), AbiValue::FixedBytes(b)) => a.eq(b),
468            (AbiValue::String(a), AbiValue::String(b)) => a.eq(b),
469            (AbiValue::Token(a), AbiValue::Token(b)) => a.eq(b),
470            (AbiValue::Tuple(a), AbiValue::Tuple(b)) => {
471                WithoutName::wrap_slice(a.as_slice()).eq(WithoutName::wrap_slice(b.as_slice()))
472            }
473            (AbiValue::Array(at, av), AbiValue::Array(bt, bv))
474            | (AbiValue::FixedArray(at, av), AbiValue::FixedArray(bt, bv)) => {
475                WithoutName::wrap(at.as_ref()).eq(WithoutName::wrap(bt.as_ref()))
476                    && WithoutName::wrap_slice(av.as_slice())
477                        .eq(WithoutName::wrap_slice(bv.as_slice()))
478            }
479            (AbiValue::Map(akt, avt, a), AbiValue::Map(bkt, bvt, b)) => {
480                akt.eq(bkt)
481                    && WithoutName::wrap(avt.as_ref()).eq(WithoutName::wrap(bvt.as_ref()))
482                    && WithoutName::wrap(a).eq(WithoutName::wrap(b))
483            }
484            (AbiValue::Optional(at, a), AbiValue::Optional(bt, b)) => {
485                WithoutName::wrap(at.as_ref()).eq(WithoutName::wrap(bt.as_ref()))
486                    && a.as_deref()
487                        .map(WithoutName::wrap)
488                        .eq(&b.as_deref().map(WithoutName::wrap))
489            }
490            (AbiValue::Ref(a), AbiValue::Ref(b)) => {
491                WithoutName::wrap(a.as_ref()).eq(WithoutName::wrap(b.as_ref()))
492            }
493            _unused => false,
494        }
495    }
496}
497
498/// ABI value which has a fixed bits representation
499/// and therefore can be used as a map key.
500#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
501pub enum PlainAbiValue {
502    /// Unsigned integer of n bits.
503    Uint(u16, BigUint),
504    /// Signed integer of n bits.
505    Int(u16, BigInt),
506    /// Boolean.
507    Bool(bool),
508    /// Internal address ([`IntAddr`]).
509    ///
510    /// [`IntAddr`]: crate::models::message::IntAddr
511    Address(Box<IntAddr>),
512}
513
514impl PlainAbiValue {
515    /// Returns whether this value has the same type as the provided one.
516    pub fn has_type(&self, ty: &PlainAbiType) -> bool {
517        match (self, ty) {
518            (Self::Uint(n, _), PlainAbiType::Uint(t)) => n == t,
519            (Self::Int(n, _), PlainAbiType::Int(t)) => n == t,
520            (Self::Bool(_), PlainAbiType::Bool) | (Self::Address(_), PlainAbiType::Address) => true,
521            _ => false,
522        }
523    }
524
525    /// Returns a printable object which will display a value type signature.
526    #[inline]
527    pub fn display_type(&self) -> impl std::fmt::Display + '_ {
528        DisplayPlainValueType(self)
529    }
530}
531
532impl From<PlainAbiValue> for AbiValue {
533    fn from(value: PlainAbiValue) -> Self {
534        match value {
535            PlainAbiValue::Uint(n, value) => Self::Uint(n, value),
536            PlainAbiValue::Int(n, value) => Self::Int(n, value),
537            PlainAbiValue::Bool(value) => Self::Bool(value),
538            PlainAbiValue::Address(value) => {
539                let addr = match value.as_ref() {
540                    IntAddr::Std(addr) => AnyAddr::Std(addr.clone()),
541                    IntAddr::Var(addr) => AnyAddr::Var(addr.clone()),
542                };
543                AbiValue::Address(Box::new(addr))
544            }
545        }
546    }
547}
548
549/// Contract header value.
550#[derive(Debug, Clone, Eq, PartialEq)]
551pub enum AbiHeader {
552    /// `time` header.
553    Time(u64),
554    /// `expire` header.
555    Expire(u32),
556    /// `pubkey` header.
557    PublicKey(Option<Box<ed25519_dalek::VerifyingKey>>),
558}
559
560impl AbiHeader {
561    /// Returns whether this value has the same type as the provided one.
562    pub fn has_type(&self, ty: &AbiHeaderType) -> bool {
563        matches!(
564            (self, ty),
565            (Self::Time(_), AbiHeaderType::Time)
566                | (Self::Expire(_), AbiHeaderType::Expire)
567                | (Self::PublicKey(_), AbiHeaderType::PublicKey)
568        )
569    }
570
571    /// Returns a printable object which will display a header type signature.
572    #[inline]
573    pub fn display_type(&self) -> impl std::fmt::Display + '_ {
574        DisplayHeaderType(self)
575    }
576}
577
578struct DisplayHeaderType<'a>(&'a AbiHeader);
579
580impl std::fmt::Display for DisplayHeaderType<'_> {
581    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
582        f.write_str(match self.0 {
583            AbiHeader::Time(_) => "time",
584            AbiHeader::Expire(_) => "expire",
585            AbiHeader::PublicKey(_) => "pubkey",
586        })
587    }
588}
589
590struct DisplayPlainValueType<'a>(&'a PlainAbiValue);
591
592impl std::fmt::Display for DisplayPlainValueType<'_> {
593    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
594        f.write_str(match self.0 {
595            PlainAbiValue::Uint(n, _) => return write!(f, "uint{n}"),
596            PlainAbiValue::Int(n, _) => return write!(f, "int{n}"),
597            PlainAbiValue::Bool(_) => "bool",
598            PlainAbiValue::Address(_) => "address",
599        })
600    }
601}
602
603struct DisplayValueType<'a>(&'a AbiValue);
604
605impl std::fmt::Display for DisplayValueType<'_> {
606    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
607        let s = match self.0 {
608            AbiValue::Uint(n, _) => return write!(f, "uint{n}"),
609            AbiValue::Int(n, _) => return write!(f, "int{n}"),
610            AbiValue::VarUint(n, _) => return write!(f, "varuint{n}"),
611            AbiValue::VarInt(n, _) => return write!(f, "varint{n}"),
612            AbiValue::Bool(_) => "bool",
613            AbiValue::Cell(_) => "cell",
614            AbiValue::Address(_) => "address",
615            AbiValue::AddressStd(_) => "address_std",
616            AbiValue::Bytes(_) => "bytes",
617            AbiValue::FixedBytes(bytes) => return write!(f, "fixedbytes{}", bytes.len()),
618            AbiValue::String(_) => "string",
619            AbiValue::Token(_) => "gram",
620            AbiValue::Tuple(items) => {
621                return std::fmt::Display::fmt(&DisplayTupleValueType(items), f);
622            }
623            AbiValue::Array(ty, _) => return write!(f, "{ty}[]"),
624            AbiValue::FixedArray(ty, items) => return write!(f, "{ty}[{}]", items.len()),
625            AbiValue::Map(key_ty, value_ty, _) => return write!(f, "map({key_ty},{value_ty})"),
626            AbiValue::Optional(ty, _) => return write!(f, "optional({ty})"),
627            AbiValue::Ref(val) => return write!(f, "ref({})", val.display_type()),
628        };
629        f.write_str(s)
630    }
631}
632
633struct DisplayTupleValueType<'a>(&'a [NamedAbiValue]);
634
635impl std::fmt::Display for DisplayTupleValueType<'_> {
636    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
637        let s = if self.0.is_empty() {
638            "()"
639        } else {
640            let mut first = true;
641            ok!(f.write_str("("));
642            for item in self.0 {
643                if !std::mem::take(&mut first) {
644                    ok!(f.write_str(","));
645                }
646                ok!(write!(f, "{}", item.value.display_type()));
647            }
648            ")"
649        };
650        f.write_str(s)
651    }
652}
653
654struct DisplayTupleType<'a>(&'a [NamedAbiType]);
655
656impl std::fmt::Display for DisplayTupleType<'_> {
657    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
658        let s = if self.0.is_empty() {
659            "()"
660        } else {
661            let mut first = true;
662            ok!(f.write_str("("));
663            for item in self.0 {
664                if !std::mem::take(&mut first) {
665                    ok!(f.write_str(","));
666                }
667                ok!(write!(f, "{}", item.ty));
668            }
669            ")"
670        };
671        f.write_str(s)
672    }
673}