1use syn::spanned::Spanned;
6
7mod generation;
8mod guid;
9pub(crate) use guid::Guid;
10
11#[cfg(test)]
12mod tests;
13
14#[proc_macro_attribute]
37pub fn interface(
38 attributes: proc_macro::TokenStream,
39 original_type: proc_macro::TokenStream,
40) -> proc_macro::TokenStream {
41 interface_core(attributes.into(), original_type.into()).into()
42}
43
44fn interface_core(
45 attributes: proc_macro2::TokenStream,
46 item_tokens: proc_macro2::TokenStream,
47) -> proc_macro2::TokenStream {
48 let guid = match syn::parse2::<Guid>(attributes) {
49 Ok(g) => g,
50 Err(e) => return e.into_compile_error(),
51 };
52 let interface = match syn::parse2::<Interface>(item_tokens) {
53 Ok(i) => i,
54 Err(e) => return e.into_compile_error(),
55 };
56 match interface.gen_tokens(&guid) {
57 Ok(t) => t,
58 Err(e) => e.into_compile_error(),
59 }
60}
61
62pub(crate) struct Interface {
64 pub(crate) visibility: syn::Visibility,
65 pub(crate) name: syn::Ident,
66 pub(crate) parent: Option<syn::Path>,
67 pub(crate) methods: Vec<InterfaceMethod>,
68 pub(crate) docs: Vec<syn::Attribute>,
69}
70
71impl syn::parse::Parse for Interface {
72 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
73 let attributes = input.call(syn::Attribute::parse_outer)?;
74 let mut docs = Vec::new();
75 for attr in attributes.into_iter() {
76 let path = attr.path();
77 if path.is_ident("doc") {
78 docs.push(attr);
79 } else {
80 return Err(syn::Error::new(path.span(), "Unrecognized attribute"));
81 }
82 }
83
84 let visibility = input.parse::<syn::Visibility>()?;
85 _ = input.parse::<syn::Token![unsafe]>()?;
86 _ = input.parse::<syn::Token![trait]>()?;
87 let name = input.parse::<syn::Ident>()?;
88 _ = input.parse::<syn::Token![:]>();
89 let parent = input.parse::<syn::Path>().ok();
90 let content;
91 syn::braced!(content in input);
92 let mut methods = Vec::new();
93 while !content.is_empty() {
94 methods.push(content.parse::<InterfaceMethod>()?);
95 }
96 Ok(Self {
97 visibility,
98 methods,
99 name,
100 parent,
101 docs,
102 })
103 }
104}
105
106pub(crate) struct InterfaceMethod {
108 pub(crate) name: syn::Ident,
109 pub(crate) visibility: syn::Visibility,
110 pub(crate) args: Vec<InterfaceMethodArg>,
111 pub(crate) ret: syn::ReturnType,
112 pub(crate) docs: Vec<syn::Attribute>,
113}
114
115impl syn::parse::Parse for InterfaceMethod {
116 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
117 let docs = input.call(syn::Attribute::parse_outer)?;
118 let visibility = input.parse::<syn::Visibility>()?;
119 let method = input.parse::<syn::TraitItemFn>()?;
120
121 if let Some(i) = docs.iter().find(|a| !a.path().is_ident("doc")) {
123 return Err(syn::Error::new(i.span(), "unexpected attribute"));
124 }
125 if let Some(i) = &method.default {
127 return Err(syn::Error::new(
128 i.span(),
129 "unexpected default method implementation",
130 ));
131 }
132
133 let sig = method.sig;
134
135 if let Some(i) = &sig.abi {
137 return Err(syn::Error::new(i.span(), "unexpected abi declaration"));
138 }
139 if let Some(i) = &sig.asyncness {
140 return Err(syn::Error::new(i.span(), "unexpected async declaration"));
141 }
142 if let Some(i) = sig.generics.params.iter().next() {
143 return Err(syn::Error::new(i.span(), "unexpected generics declaration"));
144 }
145 if let Some(i) = &sig.constness {
146 return Err(syn::Error::new(i.span(), "unexpected const declaration"));
147 }
148 if sig.receiver().is_none() {
149 return Err(syn::Error::new(
150 sig.span(),
151 "expected the method to have &self as its first argument",
152 ));
153 }
154 if let Some(i) = &sig.variadic {
155 return Err(syn::Error::new(i.span(), "unexpected variadic args"));
156 }
157
158 let args = sig
159 .inputs
160 .into_iter()
161 .filter_map(|a| match a {
162 syn::FnArg::Receiver(_) => None,
163 syn::FnArg::Typed(p) => Some(p),
164 })
165 .map(|p| {
166 Ok(InterfaceMethodArg {
167 ty: p.ty,
168 pat: p.pat,
169 })
170 })
171 .collect::<Result<Vec<InterfaceMethodArg>, syn::Error>>()?;
172
173 let ret = sig.output;
174 Ok(Self {
175 name: sig.ident,
176 visibility,
177 args,
178 ret,
179 docs,
180 })
181 }
182}
183
184pub(crate) struct InterfaceMethodArg {
186 pub(crate) ty: Box<syn::Type>,
188 pub(crate) pat: Box<syn::Pat>,
190}