1 use crate::syntax::qualified::QualifiedName;
2 use quote::IdentFragment;
3 use std::fmt::{self, Display};
4 use std::slice::Iter;
5 use syn::parse::{Error, Parse, ParseStream, Result};
6 use syn::{Expr, Ident, Lit, Meta, Token};
7 
8 mod kw {
9     syn::custom_keyword!(namespace);
10 }
11 
12 #[derive(Clone, Default)]
13 pub(crate) struct Namespace {
14     segments: Vec<Ident>,
15 }
16 
17 impl Namespace {
18     pub(crate) const ROOT: Self = Namespace {
19         segments: Vec::new(),
20     };
21 
iter(&self) -> Iter<Ident>22     pub(crate) fn iter(&self) -> Iter<Ident> {
23         self.segments.iter()
24     }
25 
parse_bridge_attr_namespace(input: ParseStream) -> Result<Self>26     pub(crate) fn parse_bridge_attr_namespace(input: ParseStream) -> Result<Self> {
27         if input.is_empty() {
28             return Ok(Namespace::ROOT);
29         }
30 
31         input.parse::<kw::namespace>()?;
32         input.parse::<Token![=]>()?;
33         let namespace = input.parse::<Namespace>()?;
34         input.parse::<Option<Token![,]>>()?;
35         Ok(namespace)
36     }
37 
parse_meta(meta: &Meta) -> Result<Self>38     pub(crate) fn parse_meta(meta: &Meta) -> Result<Self> {
39         if let Meta::NameValue(meta) = meta {
40             match &meta.value {
41                 Expr::Lit(expr) => {
42                     if let Lit::Str(lit) = &expr.lit {
43                         let segments = QualifiedName::parse_quoted(lit)?.segments;
44                         return Ok(Namespace { segments });
45                     }
46                 }
47                 Expr::Path(expr)
48                     if expr.qself.is_none()
49                         && expr
50                             .path
51                             .segments
52                             .iter()
53                             .all(|segment| segment.arguments.is_none()) =>
54                 {
55                     let segments = expr
56                         .path
57                         .segments
58                         .iter()
59                         .map(|segment| segment.ident.clone())
60                         .collect();
61                     return Ok(Namespace { segments });
62                 }
63                 _ => {}
64             }
65         }
66         Err(Error::new_spanned(meta, "unsupported namespace attribute"))
67     }
68 }
69 
70 impl Default for &Namespace {
default() -> Self71     fn default() -> Self {
72         const ROOT: &Namespace = &Namespace::ROOT;
73         ROOT
74     }
75 }
76 
77 impl Parse for Namespace {
parse(input: ParseStream) -> Result<Self>78     fn parse(input: ParseStream) -> Result<Self> {
79         let segments = QualifiedName::parse_quoted_or_unquoted(input)?.segments;
80         Ok(Namespace { segments })
81     }
82 }
83 
84 impl Display for Namespace {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result85     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
86         for segment in self {
87             write!(f, "{}$", segment)?;
88         }
89         Ok(())
90     }
91 }
92 
93 impl IdentFragment for Namespace {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result94     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
95         Display::fmt(self, f)
96     }
97 }
98 
99 impl<'a> IntoIterator for &'a Namespace {
100     type Item = &'a Ident;
101     type IntoIter = Iter<'a, Ident>;
into_iter(self) -> Self::IntoIter102     fn into_iter(self) -> Self::IntoIter {
103         self.iter()
104     }
105 }
106 
107 impl<'a> FromIterator<&'a Ident> for Namespace {
from_iter<I>(idents: I) -> Self where I: IntoIterator<Item = &'a Ident>,108     fn from_iter<I>(idents: I) -> Self
109     where
110         I: IntoIterator<Item = &'a Ident>,
111     {
112         let segments = idents.into_iter().cloned().collect();
113         Namespace { segments }
114     }
115 }
116