1use quote::quote;
2use syn::{parse_macro_input, DeriveInput, Data, FnArg, ItemFn};
3
4macro_rules! derive_handle {
5 ($name:ident) => (
6 #[proc_macro_derive($name)]
7 #[allow(non_snake_case)]
8 pub fn $name(ast: proc_macro::TokenStream) -> proc_macro::TokenStream {
9 let ast = parse_macro_input!(ast as DeriveInput);
10 let (impl_generics, type_generics, where_clause) = ast.generics.split_for_impl();
11 let struct_name = &ast.ident;
12 let k = match ast.data {
13 Data::Struct(_) => {
14 quote! {
15 impl #impl_generics crate::handle::$name for #struct_name #type_generics #where_clause {}
16 }
17 }
18 _ => panic!(concat!(stringify!($name)," can only be derived from struct")),
19 };
20 k.into()
21 }
22 );
23}
24
25derive_handle! {WritableHandle}
26derive_handle! {ReadableHandle}
27derive_handle! {CancelableIoHandle}
28derive_handle! {WaitableHandle}
29derive_handle! {DuplicatableHandle}
30
31#[proc_macro_attribute]
33pub fn ansi_fn(_attr: proc_macro::TokenStream, ast: proc_macro::TokenStream) -> proc_macro::TokenStream {
34 generate_fn(ast, true)
35}
36
37#[proc_macro_attribute]
39pub fn unicode_fn(_attr: proc_macro::TokenStream, ast: proc_macro::TokenStream) -> proc_macro::TokenStream {
40 generate_fn(ast, false)
41}
42
43fn generate_fn(ast: proc_macro::TokenStream, is_ansi: bool) -> proc_macro::TokenStream {
44 let orig_fn = parse_macro_input!(ast as ItemFn);
45 let orig_name = orig_fn.sig.ident.to_string();
46 assert!(orig_name.ends_with(if is_ansi { "_a" } else { "_w" }));
47 let ident = syn::Ident::new(&orig_name, proc_macro2::Span::call_site()); let new_ident = syn::Ident::new(&orig_name[..orig_name.len() - 2], proc_macro2::Span::call_site());
51
52 let (impl_generics, _, where_clause) = orig_fn.sig.generics.split_for_impl();
53 let vis = orig_fn.vis.clone(); let unsafety = orig_fn.sig.unsafety.clone(); let mut idents = proc_macro2::TokenStream::new();
58 for x in orig_fn.sig.inputs.iter() {
59 match x {
60 FnArg::Typed(pt) => {
61 let x = pt.pat.as_ref();
62 idents.extend(quote! {#x,});
63 }
64 _ => panic!("Unknown arg type"),
65 }
66 }
67 let rty = orig_fn.sig.output.clone(); let m = orig_fn.sig.inputs.clone(); let body = quote! { #ident(#idents) };
71
72 let new_fn = if is_ansi {
73 quote! {
74 #[cfg(feature = "ansi")]
75 #vis #unsafety fn #new_ident #impl_generics(#m) #rty #where_clause{
76 #body
77 }
78 }
79 } else {
80 quote! {
81 #[cfg(not(feature = "ansi"))]
82 #vis #unsafety fn #new_ident #impl_generics(#m) #rty #where_clause{
83 #body
84 }
85 }
86 };
87 let item = quote! { #orig_fn #new_fn };
88 item.into()
89}