Skip to main content

safer_ffi_gen_macro/
lib.rs

1use quote::ToTokens;
2use syn::{parse_macro_input, punctuated::Punctuated, Item, Meta, Token};
3
4mod enum_to_error_code;
5mod error;
6mod ffi_module;
7mod ffi_signature;
8mod ffi_type;
9mod specialization;
10#[cfg(test)]
11mod test_utils;
12mod utils;
13
14use enum_to_error_code::impl_enum_to_error_code;
15use error::{Error, ErrorReason};
16use ffi_module::{FfiModule, ImplSpecialization};
17use ffi_signature::{FfiSignature, FfiSignatureOptions, FunctionSpecialization};
18use ffi_type::process_ffi_type;
19use specialization::Specialization;
20
21#[proc_macro_attribute]
22pub fn safer_ffi_gen(
23    attr: proc_macro::TokenStream,
24    mut item: proc_macro::TokenStream,
25) -> proc_macro::TokenStream {
26    let input = {
27        let item = item.clone();
28        parse_macro_input!(item as Item)
29    };
30
31    let output = match input {
32        Item::Fn(f) => {
33            let options = parse_macro_input!(attr as FfiSignatureOptions);
34            FfiSignature::new(options, f).map(ToTokens::into_token_stream)
35        }
36        Item::Impl(impl_block) => FfiModule::new(impl_block).map(ToTokens::into_token_stream),
37        _ => Err(ErrorReason::UnsupportedItemType.spanned(input)),
38    };
39
40    let output = output
41        .map_err(Into::into)
42        .unwrap_or_else(syn::Error::into_compile_error);
43
44    item.extend([proc_macro::TokenStream::from(output)]);
45    item
46}
47
48/// Marker to ignore functions in `impl` block
49#[proc_macro_attribute]
50pub fn safer_ffi_gen_ignore(
51    _: proc_macro::TokenStream,
52    item: proc_macro::TokenStream,
53) -> proc_macro::TokenStream {
54    item
55}
56
57#[proc_macro_attribute]
58pub fn ffi_type(
59    args: proc_macro::TokenStream,
60    input: proc_macro::TokenStream,
61) -> proc_macro::TokenStream {
62    let args = parse_macro_input!(args with Punctuated::<Meta, Token![,]>::parse_terminated);
63    let ty_def = parse_macro_input!(input as syn::Item);
64
65    process_ffi_type(args, ty_def)
66        .map(ToTokens::into_token_stream)
67        .map_err(Into::into)
68        .unwrap_or_else(syn::Error::into_compile_error)
69        .into()
70}
71
72#[proc_macro_attribute]
73pub fn enum_to_error_code(
74    _: proc_macro::TokenStream,
75    item: proc_macro::TokenStream,
76) -> proc_macro::TokenStream {
77    let mut input = item.clone();
78    let enum_def = parse_macro_input!(item as syn::ItemEnum);
79    let generated = impl_enum_to_error_code(enum_def)
80        .map_err(Into::into)
81        .unwrap_or_else(syn::Error::into_compile_error);
82    input.extend(proc_macro::TokenStream::from(generated));
83    input
84}
85
86#[proc_macro]
87pub fn specialize(args: proc_macro::TokenStream) -> proc_macro::TokenStream {
88    let decl = parse_macro_input!(args as Specialization);
89    decl.to_token_stream().into()
90}
91
92#[doc(hidden)]
93#[proc_macro]
94pub fn __specialize_impl(args: proc_macro::TokenStream) -> proc_macro::TokenStream {
95    let specialization = parse_macro_input!(args as ImplSpecialization);
96    specialization.to_token_stream().into()
97}
98
99#[doc(hidden)]
100#[proc_macro]
101pub fn __specialize_function(args: proc_macro::TokenStream) -> proc_macro::TokenStream {
102    let specialization = parse_macro_input!(args as FunctionSpecialization);
103    specialization.to_token_stream().into()
104}