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