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