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