syn_solidity/ident/
path.rs

1use crate::{SolIdent, Spanned};
2use proc_macro2::{Ident, Span};
3use std::{
4    fmt,
5    ops::{Deref, DerefMut},
6};
7use syn::{
8    ext::IdentExt,
9    parse::{Parse, ParseStream},
10    punctuated::Punctuated,
11    Result, Token,
12};
13
14/// Create a [`SolPath`] from a list of identifiers.
15#[macro_export]
16macro_rules! sol_path {
17    () => { $crate::SolPath::new() };
18
19    ($($e:expr),+) => {{
20        let mut path = $crate::SolPath::new();
21        $(path.push($crate::SolIdent::from($e));)+
22        path
23    }};
24}
25
26/// A list of identifiers, separated by dots.
27///
28/// This is never parsed as empty.
29#[derive(Clone, PartialEq, Eq, Hash)]
30pub struct SolPath(Punctuated<SolIdent, Token![.]>);
31
32impl Deref for SolPath {
33    type Target = Punctuated<SolIdent, Token![.]>;
34
35    fn deref(&self) -> &Self::Target {
36        &self.0
37    }
38}
39
40impl DerefMut for SolPath {
41    fn deref_mut(&mut self) -> &mut Self::Target {
42        &mut self.0
43    }
44}
45
46impl fmt::Display for SolPath {
47    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48        for (i, ident) in self.0.iter().enumerate() {
49            if i > 0 {
50                f.write_str(".")?;
51            }
52            ident.fmt(f)?;
53        }
54        Ok(())
55    }
56}
57
58impl fmt::Debug for SolPath {
59    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60        f.debug_list().entries(&self.0).finish()
61    }
62}
63
64impl FromIterator<SolIdent> for SolPath {
65    fn from_iter<T: IntoIterator<Item = SolIdent>>(iter: T) -> Self {
66        Self(iter.into_iter().collect())
67    }
68}
69
70impl Parse for SolPath {
71    fn parse(input: ParseStream<'_>) -> Result<Self> {
72        // Modified from: `syn::Path::parse_mod_style`
73        let mut segments = Punctuated::new();
74        loop {
75            if !input.peek(Ident::peek_any) {
76                break;
77            }
78            segments.push_value(input.parse()?);
79            if !input.peek(Token![.]) {
80                break;
81            }
82            segments.push_punct(input.parse()?);
83        }
84
85        if segments.is_empty() {
86            Err(input.parse::<SolIdent>().unwrap_err())
87        } else if segments.trailing_punct() {
88            Err(input.error("expected path segment after `.`"))
89        } else {
90            Ok(Self(segments))
91        }
92    }
93}
94
95impl Spanned for SolPath {
96    fn span(&self) -> Span {
97        self.0.span()
98    }
99
100    fn set_span(&mut self, span: Span) {
101        self.0.set_span(span);
102    }
103}
104
105impl Default for SolPath {
106    fn default() -> Self {
107        Self::new()
108    }
109}
110
111impl SolPath {
112    pub const fn new() -> Self {
113        Self(Punctuated::new())
114    }
115
116    pub fn first(&self) -> &SolIdent {
117        self.0.first().unwrap()
118    }
119
120    pub fn first_mut(&mut self) -> &mut SolIdent {
121        self.0.first_mut().unwrap()
122    }
123
124    pub fn last(&self) -> &SolIdent {
125        self.0.last().unwrap()
126    }
127
128    pub fn last_mut(&mut self) -> &mut SolIdent {
129        self.0.last_mut().unwrap()
130    }
131}