1 use crate::syntax::cfg::CfgExpr;
2 use crate::syntax::namespace::Namespace;
3 use quote::quote;
4 use syn::parse::{Error, Parse, ParseStream, Result};
5 use syn::{
6     braced, token, Abi, Attribute, ForeignItem, Ident, Item as RustItem, ItemEnum, ItemImpl,
7     ItemStruct, ItemUse, LitStr, Token, Visibility,
8 };
9 
10 pub(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 
27 pub(crate) enum Item {
28     Struct(ItemStruct),
29     Enum(ItemEnum),
30     ForeignMod(ItemForeignMod),
31     Use(ItemUse),
32     Impl(ItemImpl),
33     Other(RustItem),
34 }
35 
36 pub(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 
45 impl Parse for Module {
parse(input: ParseStream) -> Result<Self>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 
87 impl Parse for Item {
parse(input: ParseStream) -> Result<Self>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 }
134