cxx_build/syntax/
namespace.rs

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