1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#![forbid(unsafe_code)]
use autocxx_parser::{IncludeCpp, SubclassAttrs};
use proc_macro::TokenStream;
use proc_macro2::{Ident, Span};
use proc_macro_error::{abort, proc_macro_error};
use quote::quote;
use syn::parse::Parser;
use syn::{parse_macro_input, parse_quote, Fields, Item, ItemStruct, Visibility};
#[proc_macro_error]
#[proc_macro]
pub fn include_cpp_impl(input: TokenStream) -> TokenStream {
let include_cpp = parse_macro_input!(input as IncludeCpp);
TokenStream::from(include_cpp.generate_rs())
}
#[proc_macro_error]
#[proc_macro_attribute]
pub fn subclass(attr: TokenStream, item: TokenStream) -> TokenStream {
let mut s: ItemStruct =
syn::parse(item).unwrap_or_else(|_| abort!(Span::call_site(), "Expected a struct"));
if !matches!(s.vis, Visibility::Public(..)) {
use syn::spanned::Spanned;
abort!(s.vis.span(), "Rust subclasses of C++ types must by public");
}
let id = &s.ident;
let cpp_ident = Ident::new(&format!("{}Cpp", id), Span::call_site());
let input = quote! {
cpp_peer: autocxx::subclass::CppSubclassCppPeerHolder<ffi:: #cpp_ident>
};
let parser = syn::Field::parse_named;
let new_field = parser.parse2(input).unwrap();
s.fields = match &mut s.fields {
Fields::Named(fields) => {
fields.named.push(new_field);
s.fields
},
Fields::Unit => Fields::Named(parse_quote! {
{
#new_field
}
}),
_ => abort!(Span::call_site(), "Expect a struct with named fields - use struct A{} or struct A; as opposed to struct A()"),
};
let subclass_attrs: SubclassAttrs = syn::parse(attr)
.unwrap_or_else(|_| abort!(Span::call_site(), "Unable to parse attributes"));
let self_owned_bit = if subclass_attrs.self_owned {
Some(quote! {
impl autocxx::subclass::CppSubclassSelfOwned<ffi::#cpp_ident> for #id {}
})
} else {
None
};
let toks = quote! {
#s
impl autocxx::subclass::CppSubclass<ffi::#cpp_ident> for #id {
fn peer_holder_mut(&mut self) -> &mut autocxx::subclass::CppSubclassCppPeerHolder<ffi::#cpp_ident> {
&mut self.cpp_peer
}
fn peer_holder(&self) -> &autocxx::subclass::CppSubclassCppPeerHolder<ffi::#cpp_ident> {
&self.cpp_peer
}
}
#self_owned_bit
};
toks.into()
}
#[proc_macro_error]
#[proc_macro_attribute]
pub fn extern_rust_type(attr: TokenStream, input: TokenStream) -> TokenStream {
if !attr.is_empty() {
abort!(Span::call_site(), "Expected no attributes");
}
let i: Item =
syn::parse(input.clone()).unwrap_or_else(|_| abort!(Span::call_site(), "Expected an item"));
match i {
Item::Struct(..) | Item::Enum(..) | Item::Fn(..) => {}
_ => abort!(Span::call_site(), "Expected a struct or enum"),
}
input
}
#[proc_macro_error]
#[proc_macro_attribute]
pub fn extern_rust_function(attr: TokenStream, input: TokenStream) -> TokenStream {
if !attr.is_empty() {
abort!(Span::call_site(), "Expected no attributes");
}
let i: Item =
syn::parse(input.clone()).unwrap_or_else(|_| abort!(Span::call_site(), "Expected an item"));
match i {
Item::Fn(..) => {}
_ => abort!(Span::call_site(), "Expected a function"),
}
input
}
#[proc_macro_error]
#[proc_macro_attribute]
pub fn cpp_semantics(_attr: TokenStream, _input: TokenStream) -> TokenStream {
abort!(
Span::call_site(),
"Please do not attempt to compile this code. \n\
This code is the output from the autocxx-specific version of bindgen, \n\
and should be interpreted by autocxx-engine before further usage."
);
}