cxx_gen/syntax/
file.rs

1use crate::syntax::cfg::CfgExpr;
2use crate::syntax::namespace::Namespace;
3use quote::quote;
4use syn::parse::{Error, Parse, ParseStream, Result};
5use syn::{
6    braced, token, Abi, Attribute, ForeignItem, Ident, Item as RustItem, ItemEnum, ItemImpl,
7    ItemStruct, ItemUse, LitStr, Token, Visibility,
8};
9
10pub(crate) struct Module {
11    #[allow(dead_code)]
12    pub cfg: CfgExpr,
13    pub namespace: Namespace,
14    pub attrs: Vec<Attribute>,
15    #[allow(dead_code)] // only used by cxxbridge-macro, not cxx-build
16    pub vis: Visibility,
17    pub unsafety: Option<Token![unsafe]>,
18    #[allow(dead_code)] // only used by cxxbridge-macro, not cxx-build
19    pub mod_token: Token![mod],
20    #[allow(dead_code)] // only used by cxxbridge-macro, not cxx-build
21    pub ident: Ident,
22    #[allow(dead_code)] // only used by cxxbridge-macro, not cxx-build
23    pub brace_token: token::Brace,
24    pub content: Vec<Item>,
25}
26
27pub(crate) enum Item {
28    Struct(ItemStruct),
29    Enum(ItemEnum),
30    ForeignMod(ItemForeignMod),
31    Use(ItemUse),
32    Impl(ItemImpl),
33    Other(RustItem),
34}
35
36pub(crate) struct ItemForeignMod {
37    pub attrs: Vec<Attribute>,
38    pub unsafety: Option<Token![unsafe]>,
39    pub abi: Abi,
40    #[allow(dead_code)]
41    pub brace_token: token::Brace,
42    pub items: Vec<ForeignItem>,
43}
44
45impl Parse for Module {
46    fn parse(input: ParseStream) -> Result<Self> {
47        let cfg = CfgExpr::Unconditional;
48        let namespace = Namespace::ROOT;
49        let mut attrs = input.call(Attribute::parse_outer)?;
50        let vis: Visibility = input.parse()?;
51        let unsafety: Option<Token![unsafe]> = input.parse()?;
52        let mod_token: Token![mod] = input.parse()?;
53        let ident: Ident = input.parse()?;
54
55        let semi: Option<Token![;]> = input.parse()?;
56        if let Some(semi) = semi {
57            let span = quote!(#vis #mod_token #semi);
58            return Err(Error::new_spanned(
59                span,
60                "#[cxx::bridge] module must have inline contents",
61            ));
62        }
63
64        let content;
65        let brace_token = braced!(content in input);
66        attrs.extend(content.call(Attribute::parse_inner)?);
67
68        let mut items = Vec::new();
69        while !content.is_empty() {
70            items.push(content.parse()?);
71        }
72
73        Ok(Module {
74            cfg,
75            namespace,
76            attrs,
77            vis,
78            unsafety,
79            mod_token,
80            ident,
81            brace_token,
82            content: items,
83        })
84    }
85}
86
87impl Parse for Item {
88    fn parse(input: ParseStream) -> Result<Self> {
89        let attrs = input.call(Attribute::parse_outer)?;
90
91        let ahead = input.fork();
92        let unsafety = if ahead.parse::<Option<Token![unsafe]>>()?.is_some()
93            && ahead.parse::<Option<Token![extern]>>()?.is_some()
94            && ahead.parse::<Option<LitStr>>().is_ok()
95            && ahead.peek(token::Brace)
96        {
97            Some(input.parse()?)
98        } else {
99            None
100        };
101
102        let item = input.parse()?;
103        match item {
104            RustItem::Struct(mut item) => {
105                item.attrs.splice(..0, attrs);
106                Ok(Item::Struct(item))
107            }
108            RustItem::Enum(mut item) => {
109                item.attrs.splice(..0, attrs);
110                Ok(Item::Enum(item))
111            }
112            RustItem::ForeignMod(mut item) => {
113                item.attrs.splice(..0, attrs);
114                Ok(Item::ForeignMod(ItemForeignMod {
115                    attrs: item.attrs,
116                    unsafety,
117                    abi: item.abi,
118                    brace_token: item.brace_token,
119                    items: item.items,
120                }))
121            }
122            RustItem::Impl(mut item) => {
123                item.attrs.splice(..0, attrs);
124                Ok(Item::Impl(item))
125            }
126            RustItem::Use(mut item) => {
127                item.attrs.splice(..0, attrs);
128                Ok(Item::Use(item))
129            }
130            other => Ok(Item::Other(other)),
131        }
132    }
133}