syn_solidity/type/
tuple.rs1use crate::{kw, utils::DebugPunctuated, Spanned, Type};
2use proc_macro2::Span;
3use std::{
4 fmt,
5 hash::{Hash, Hasher},
6};
7use syn::{
8 parenthesized,
9 parse::{Parse, ParseStream},
10 punctuated::Punctuated,
11 token::Paren,
12 Error, Result, Token,
13};
14
15#[derive(Clone)]
17pub struct TypeTuple {
18 pub tuple_token: Option<kw::tuple>,
19 pub paren_token: Paren,
20 pub types: Punctuated<Type, Token![,]>,
21}
22
23impl PartialEq for TypeTuple {
24 fn eq(&self, other: &Self) -> bool {
25 self.types == other.types
26 }
27}
28
29impl Eq for TypeTuple {}
30
31impl Hash for TypeTuple {
32 fn hash<H: Hasher>(&self, state: &mut H) {
33 self.types.hash(state);
34 }
35}
36
37impl fmt::Display for TypeTuple {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 f.write_str("(")?;
40 for (i, ty) in self.types.iter().enumerate() {
41 if i > 0 {
42 f.write_str(",")?;
43 }
44 ty.fmt(f)?;
45 }
46 if self.types.len() == 1 {
47 f.write_str(",")?;
48 }
49 f.write_str(")")
50 }
51}
52
53impl fmt::Debug for TypeTuple {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 f.debug_tuple("TypeTuple").field(DebugPunctuated::new(&self.types)).finish()
56 }
57}
58
59impl Parse for TypeTuple {
60 fn parse(input: ParseStream<'_>) -> Result<Self> {
61 let content;
62 let this = Self {
63 tuple_token: input.parse()?,
64 paren_token: parenthesized!(content in input),
65 types: content.parse_terminated(Type::parse, Token![,])?,
66 };
67 match this.types.len() {
68 0 => Err(Error::new(this.paren_token.span.join(), "empty tuples are not allowed")),
69 1 if !this.types.trailing_punct() => Err(Error::new(
70 this.paren_token.span.close(),
71 "single element tuples must have a trailing comma",
72 )),
73 _ => Ok(this),
74 }
75 }
76}
77
78impl FromIterator<Type> for TypeTuple {
79 fn from_iter<T: IntoIterator<Item = Type>>(iter: T) -> Self {
80 Self {
81 tuple_token: None,
82 paren_token: Paren::default(),
83 types: {
84 let mut types = iter.into_iter().collect::<Punctuated<_, _>>();
85 if !types.trailing_punct() && types.len() == 1 {
87 types.push_punct(Default::default());
88 }
89 types
90 },
91 }
92 }
93}
94
95impl Spanned for TypeTuple {
96 fn span(&self) -> Span {
97 let span = self.paren_token.span.join();
98 self.tuple_token.and_then(|tuple_token| tuple_token.span.join(span)).unwrap_or(span)
99 }
100
101 fn set_span(&mut self, span: Span) {
102 if let Some(tuple_token) = &mut self.tuple_token {
103 tuple_token.span = span;
104 }
105 self.paren_token = Paren(span);
106 }
107}
108
109impl TypeTuple {
110 pub fn is_abi_dynamic(&self) -> bool {
112 self.types.iter().any(Type::is_abi_dynamic)
113 }
114}