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