syn_solidity/type/
tuple.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use crate::{kw, utils::DebugPunctuated, Spanned, Type};
use proc_macro2::Span;
use std::{
    fmt,
    hash::{Hash, Hasher},
};
use syn::{
    parenthesized,
    parse::{Parse, ParseStream},
    punctuated::Punctuated,
    token::Paren,
    Error, Result, Token,
};

/// A tuple type.
#[derive(Clone)]
pub struct TypeTuple {
    pub tuple_token: Option<kw::tuple>,
    pub paren_token: Paren,
    pub types: Punctuated<Type, Token![,]>,
}

impl PartialEq for TypeTuple {
    fn eq(&self, other: &Self) -> bool {
        self.types == other.types
    }
}

impl Eq for TypeTuple {}

impl Hash for TypeTuple {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.types.hash(state);
    }
}

impl fmt::Display for TypeTuple {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("(")?;
        for (i, ty) in self.types.iter().enumerate() {
            if i > 0 {
                f.write_str(",")?;
            }
            ty.fmt(f)?;
        }
        if self.types.len() == 1 {
            f.write_str(",")?;
        }
        f.write_str(")")
    }
}

impl fmt::Debug for TypeTuple {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_tuple("TypeTuple").field(DebugPunctuated::new(&self.types)).finish()
    }
}

impl Parse for TypeTuple {
    fn parse(input: ParseStream<'_>) -> Result<Self> {
        let content;
        let this = Self {
            tuple_token: input.parse()?,
            paren_token: parenthesized!(content in input),
            types: content.parse_terminated(Type::parse, Token![,])?,
        };
        match this.types.len() {
            0 => Err(Error::new(this.paren_token.span.join(), "empty tuples are not allowed")),
            1 if !this.types.trailing_punct() => Err(Error::new(
                this.paren_token.span.close(),
                "single element tuples must have a trailing comma",
            )),
            _ => Ok(this),
        }
    }
}

impl FromIterator<Type> for TypeTuple {
    fn from_iter<T: IntoIterator<Item = Type>>(iter: T) -> Self {
        Self {
            tuple_token: None,
            paren_token: Paren::default(),
            types: {
                let mut types = iter.into_iter().collect::<Punctuated<_, _>>();
                // ensure trailing comma for single item tuple
                if !types.trailing_punct() && types.len() == 1 {
                    types.push_punct(Default::default());
                }
                types
            },
        }
    }
}

impl Spanned for TypeTuple {
    fn span(&self) -> Span {
        let span = self.paren_token.span.join();
        self.tuple_token.and_then(|tuple_token| tuple_token.span.join(span)).unwrap_or(span)
    }

    fn set_span(&mut self, span: Span) {
        if let Some(tuple_token) = &mut self.tuple_token {
            tuple_token.span = span;
        }
        self.paren_token = Paren(span);
    }
}

impl TypeTuple {
    /// See [`Type::is_abi_dynamic`].
    pub fn is_abi_dynamic(&self) -> bool {
        self.types.iter().any(Type::is_abi_dynamic)
    }
}