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)] pub vis: Visibility,
17 pub unsafety: Option<Token![unsafe]>,
18 #[allow(dead_code)] pub mod_token: Token![mod],
20 #[allow(dead_code)] pub ident: Ident,
22 #[allow(dead_code)] 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}