[go: up one dir, main page]

ffi/
lib.rs

1// Copyright (C) 2023-2024 Intel Corporation, Rowan Hart
2// SPDX-License-Identifier: Apache-2.0
3
4//! The `ffi` macro allows you to easily export FFI interfaces for your Rust code with minimal
5//! boilerplate. It is designed to facilitate several unique use cases which commonly occur in
6//! FFI code, particularly where a Rust shared library is `dlopen`ed by a C program and called
7//! into.
8//!
9//! * Callbacks from C to Rust code using opaque pointers to Rust objects
10//! * Callbacks in C code to Rust code where passing a closure is preferred to passing a
11//!   function pointer, for example where state capture is desired.
12
13#![deny(clippy::unwrap_used)]
14#![forbid(unsafe_code)]
15
16use darling::{
17    ast::NestedMeta,
18    util::{Flag, WithOriginal},
19    Error, FromAttributes, FromMeta, Result,
20};
21use proc_macro::TokenStream;
22use proc_macro2::TokenStream as TokenStream2;
23use proc_macro_error::{abort, proc_macro_error};
24use quote::{format_ident, quote};
25use std::collections::HashMap;
26use syn::{
27    parse_macro_input, parse_str, FnArg, GenericArgument, ImplGenerics, ImplItem, ImplItemFn,
28    ItemImpl, Pat, PathArguments, ReturnType, Type, TypeGenerics, WhereClause,
29};
30
31#[derive(Debug, Clone, FromMeta)]
32#[darling(and_then = "Self::validate")]
33/// Options for an argument to an ffi method
34struct FfiMethodOptArg {
35    #[darling(rename = "self")]
36    /// Whether this argument needs to be converted to the receiver type
37    receiver: Flag,
38    #[darling(default)]
39    ty: Option<String>,
40    #[darling(default)]
41    rename: Option<String>,
42    rest: Flag,
43}
44
45impl FfiMethodOptArg {
46    fn validate(self) -> Result<Self> {
47        if self.receiver.is_present() && self.rest.is_present() {
48            Err(Error::custom(
49                "An argument may either be self or have rest enabled.",
50            ))
51        } else if self.rest.is_present() && (self.ty.is_some() || self.rename.is_some()) {
52            Err(Error::custom(
53                "The rest argument may not specify a rename or type change",
54            ))
55        } else {
56            Ok(self)
57        }
58    }
59}
60
61#[derive(Debug, FromAttributes)]
62#[darling(
63    attributes(ffi),
64    forward_attrs(
65        cfg,
66        derive,
67        allow,
68        warn,
69        deny,
70        forbid,
71        deprecated,
72        must_use,
73        doc,
74        non_exhaustive
75    )
76)]
77struct FfiMethodOpts {
78    expect: Flag,
79    #[darling(default)]
80    visibility: Option<String>,
81    #[darling(default)]
82    name: Option<String>,
83    #[darling(multiple)]
84    arg: Vec<FfiMethodOptArg>,
85}
86
87impl FfiMethodOpts {
88    fn visibility(&self) -> TokenStream2 {
89        if let Some(ref visibility) = self.visibility {
90            match parse_str(visibility) {
91                Ok(visibility) => visibility,
92                Err(e) => Error::from(e).write_errors(),
93            }
94        } else {
95            // NOTE: Default is "pub" because typically this is required for FFI
96            quote!(pub)
97        }
98    }
99}
100
101struct FfiFuncRename {
102    rename: String,
103    _ty: Box<Type>,
104}
105
106struct FfiFuncArgs {
107    name: Option<TokenStream2>,
108    args: Vec<TokenStream2>,
109    renames: HashMap<usize, FfiFuncRename>,
110}
111
112#[derive(Debug)]
113struct FfiMethods<'a> {
114    ffi_self_ty: Option<Type>,
115    expect: Flag,
116    self_ty: Type,
117    self_generics: (ImplGenerics<'a>, TypeGenerics<'a>, Option<&'a WhereClause>),
118    ffi_methods: Vec<WithOriginal<FfiMethodOpts, ImplItemFn>>,
119    other_items: Vec<&'a ImplItem>,
120}
121
122impl<'a> FfiMethods<'a> {
123    fn try_from(value: &'a ItemImpl, ffi_self_ty: Option<Type>, expect: Flag) -> Result<Self> {
124        let self_generics = value.generics.split_for_impl();
125        let mut ffi_methods = Vec::new();
126        let mut other_items = Vec::new();
127        let mut errors = Vec::new();
128
129        value.items.iter().for_each(|i| {
130            if let ImplItem::Fn(ref f) = i {
131                match FfiMethodOpts::from_attributes(&f.attrs) {
132                    Ok(opts) => {
133                        let mut f = f.clone();
134                        // NOTE: This effectively makes splitting the ffi() macro across multiple invocations
135                        // an error. I'm okay with that, I don't like the syntax and it'll break the argument
136                        // ordering anyway.
137                        f.attrs
138                            .retain(|a| FfiMethodOpts::from_attributes(&[a.clone()]).is_err());
139                        ffi_methods.push(WithOriginal::new(opts, f));
140                    }
141                    Err(e) => errors.push(e),
142                }
143            } else {
144                other_items.push(i);
145            }
146        });
147
148        if !errors.is_empty() {
149            Err(Error::multiple(errors))
150        } else {
151            Ok(Self {
152                ffi_self_ty,
153                expect,
154                self_ty: *value.self_ty.clone(),
155                self_generics,
156                ffi_methods,
157                other_items,
158            })
159        }
160    }
161}
162
163impl<'a> FfiMethods<'a> {
164    fn original(&self) -> TokenStream2 {
165        let orig_ffi_methods = self
166            .ffi_methods
167            .iter()
168            .map(|m| &m.original)
169            .collect::<Vec<_>>();
170
171        let other_items = &self.other_items;
172
173        quote! {
174            #(#orig_ffi_methods)*
175            #(#other_items)*
176        }
177    }
178
179    fn ffi_return_ty(return_ty: &ReturnType, expect: bool) -> (TokenStream2, TokenStream2, bool) {
180        if expect {
181            if let ReturnType::Type(_, t) = return_ty {
182                if let Type::Path(p) = &**t {
183                    if let Some(last) = p.path.segments.last() {
184                        if last.ident == "Result" {
185                            if let PathArguments::AngleBracketed(a) = &last.arguments {
186                                return (
187                                    quote!(#return_ty),
188                                    a.args
189                                        .first()
190                                        .map(|a| quote!(-> #a))
191                                        .unwrap_or(quote!(#return_ty)),
192                                    true,
193                                );
194                            }
195                        }
196                    }
197                }
198            }
199        }
200
201        (quote!(#return_ty), quote!(#return_ty), false)
202    }
203
204    fn ffi_func_name(&self, method: &WithOriginal<FfiMethodOpts, ImplItemFn>) -> TokenStream2 {
205        method
206            .parsed
207            .name
208            .as_ref()
209            .map(|n| {
210                let name = format_ident!("{n}");
211                quote!(#name)
212            })
213            .unwrap_or({
214                let name = &method.original.sig.ident;
215                quote!(#name)
216            })
217    }
218
219    fn ffi_func_args(
220        &self,
221        method: &WithOriginal<FfiMethodOpts, ImplItemFn>,
222    ) -> Result<FfiFuncArgs> {
223        let impl_method_args = method.original.sig.inputs.iter().collect::<Vec<_>>();
224        let impl_method_args_no_receiver = method
225            .original
226            .sig
227            .inputs
228            .iter()
229            .filter(|a| !matches!(a, FnArg::Receiver(_)))
230            .cloned()
231            .collect::<Vec<_>>();
232        let mut name = None;
233        let mut args = Vec::new();
234        let mut renames = HashMap::new();
235
236        for (i, arg) in method.parsed.arg.iter().enumerate() {
237            if arg.receiver.is_present() {
238                let ty = if let Some(ref ty) = arg.ty {
239                    match parse_str::<Type>(ty) {
240                        Ok(ty) => quote!(#ty),
241                        Err(e) => Error::from(e).write_errors(),
242                    }
243                } else if let Some(ref ty) = self.ffi_self_ty {
244                    quote!(#ty)
245                } else {
246                    let ty = &self.self_ty;
247                    quote!(#ty)
248                };
249
250                let arg_name = arg
251                    .rename
252                    .as_ref()
253                    .map(|n| {
254                        let n = format_ident!("{n}");
255                        quote!(#n)
256                    })
257                    .unwrap_or(quote!(slf));
258                args.push(quote!(#arg_name: #ty));
259                name = Some(arg_name);
260            } else if arg.rest.is_present() {
261                // If we have already seen the receiver argument, we need to look one
262                // argument forward
263                let mut arg_index = i;
264
265                if name.is_none() {
266                    arg_index += 1;
267                }
268
269                args.extend(
270                    impl_method_args_no_receiver
271                        .iter()
272                        .enumerate()
273                        .filter_map(|(i, a)| (i >= arg_index - 1).then_some(a))
274                        .map(|a| quote!(#a)),
275                );
276            } else if args.len() <= impl_method_args_no_receiver.len() + 1 {
277                // If we have already seen the receiver argument, we need to look one
278                // argument forward
279                let mut arg_index = i;
280
281                if name.is_none() {
282                    arg_index += 1;
283                }
284
285                let Some(FnArg::Typed(impl_method_arg_pat_type)) = impl_method_args.get(arg_index)
286                else {
287                    return Err(Error::custom(
288                        "Argument is not a typed argument while getting ffi function arguments",
289                    ));
290                };
291
292                let ty = &impl_method_arg_pat_type.ty;
293                if let Some(ref rename) = arg.rename {
294                    renames.insert(
295                        i,
296                        FfiFuncRename {
297                            rename: rename.clone(),
298                            _ty: ty.clone(),
299                        },
300                    );
301                    args.push({
302                        let rename = format_ident!("{rename}");
303                        quote!(#rename: #ty)
304                    });
305                } else {
306                    args.push(quote!(#impl_method_arg_pat_type));
307                }
308            } else {
309                return Err(Error::custom(
310                    "Argument is not a typed argument while getting ffi function arguments",
311                ));
312            }
313        }
314
315        Ok(FfiFuncArgs {
316            name,
317            args,
318            renames,
319        })
320    }
321
322    fn ffi_method_call(
323        &self,
324        method: &WithOriginal<FfiMethodOpts, ImplItemFn>,
325        ffi_receiver_name: &Option<TokenStream2>,
326        ffi_func_renames: &HashMap<usize, FfiFuncRename>,
327        need_expect: bool,
328    ) -> TokenStream2 {
329        let impl_method_args_no_receiver = method
330            .original
331            .sig
332            .inputs
333            .iter()
334            .filter(|a| !matches!(a, FnArg::Receiver(_)))
335            .cloned()
336            .collect::<Vec<_>>();
337        let Some(impl_method_receiver) = method.original.sig.receiver() else {
338            abort!(method.original, "No receiver on method");
339        };
340
341        let maybe_mut_ref = impl_method_receiver.mutability.map(|m| quote!(#m));
342        let self_ty = &self.self_ty;
343        let Some(self_name) = ffi_receiver_name else {
344            return Error::custom("No receiver name").write_errors();
345        };
346        let impl_method_name = &method.original.sig.ident;
347        let mut impl_method_call_args = Vec::new();
348        for (i, arg) in impl_method_args_no_receiver.iter().enumerate() {
349            if let Some(rename) = ffi_func_renames.get(&i) {
350                let ident = format_ident!("{}", rename.rename);
351                impl_method_call_args.push(quote!(#ident));
352            } else {
353                let FnArg::Typed(ref typed) = arg else {
354                    return Error::custom(format!("Argument {i} is not a typed argument"))
355                        .write_errors();
356                };
357                let Pat::Ident(ref ident) = &*typed.pat else {
358                    return Error::custom("Pattern is not an identifier").write_errors();
359                };
360                let ident = &ident.ident;
361                impl_method_call_args.push(quote!(#ident));
362            }
363        }
364        let impl_maybe_expect = ((method.parsed.expect.is_present() || self.expect.is_present())
365            && need_expect)
366            .then_some({
367                let expect_message =
368                    format!("Failed to execute FFI method {}", method.original.sig.ident);
369                quote!(.expect(#expect_message))
370            })
371            .unwrap_or_default();
372        quote! {
373            Into::<&#maybe_mut_ref #self_ty>::into(#self_name).#impl_method_name(
374                #(#impl_method_call_args),*
375            )#impl_maybe_expect
376        }
377    }
378
379    fn ffi_method(&self, method: &WithOriginal<FfiMethodOpts, ImplItemFn>) -> Result<TokenStream2> {
380        let ffi_func_name = self.ffi_func_name(method);
381        let ffi_func_args = self.ffi_func_args(method)?;
382
383        let (_impl_method_return_ty, ffi_func_return_ty, need_expect) = Self::ffi_return_ty(
384            &method.original.sig.output,
385            method.parsed.expect.is_present() || self.expect.is_present(),
386        );
387
388        let impl_method_args_no_receiver = method
389            .original
390            .sig
391            .inputs
392            .iter()
393            .filter(|a| !matches!(a, FnArg::Receiver(_)))
394            .cloned()
395            .collect::<Vec<_>>();
396
397        let mut impl_method_call_args = Vec::new();
398
399        for (i, arg) in impl_method_args_no_receiver.iter().enumerate() {
400            if let Some(rename) = ffi_func_args.renames.get(&i) {
401                let ident = format_ident!("{}", rename.rename);
402                impl_method_call_args.push(quote!(#ident));
403            } else {
404                let FnArg::Typed(ref typed) = arg else {
405                    return Err(Error::custom(format!(
406                        "Argument {i} is not a typed argument"
407                    )));
408                };
409                let Pat::Ident(ref ident) = &*typed.pat else {
410                    return Err(Error::custom("Pattern is not an identifier"));
411                };
412                let ident = &ident.ident;
413                impl_method_call_args.push(quote!(#ident));
414            }
415        }
416
417        let ffi_func_visibility = method.parsed.visibility();
418        let (_self_impl_genrics, self_ty_generics, self_where_clause) = &self.self_generics;
419
420        let impl_method_call = self.ffi_method_call(
421            method,
422            &ffi_func_args.name,
423            &ffi_func_args.renames,
424            need_expect,
425        );
426        let ffi_func_args = ffi_func_args.args;
427
428        Ok(quote! {
429            #[no_mangle]
430            #ffi_func_visibility extern "C" fn #ffi_func_name #self_ty_generics(
431                #(#ffi_func_args),*
432            ) #ffi_func_return_ty #self_where_clause {
433                #impl_method_call
434            }
435        })
436    }
437
438    fn ffi(&self) -> Result<TokenStream2> {
439        let methods = self
440            .ffi_methods
441            .iter()
442            .map(|m| self.ffi_method(m))
443            .collect::<Result<Vec<_>>>()?;
444
445        Ok(quote! {
446            #(#methods)*
447        })
448    }
449}
450
451#[derive(Debug, FromMeta)]
452/// Arguments to the `#[ffi()]` macro
453struct FfiOpts {
454    #[darling(default, rename = "mod_name")]
455    /// The name of the module to create to contain the FFI functions. Defaults to the name of
456    /// the type being implemented, converted to lowercase.
457    name: Option<String>,
458    #[darling(default)]
459    /// The visibility of the module to create to contain the FFI functions. Defaults to `pub`.
460    visibility: Option<String>,
461    #[darling(default)]
462    /// The self type to use for the receiver argument for all methods. Defaults to a mut
463    /// pointer to the type being implemented.
464    self_ty: Option<String>,
465    /// Whether method which return a `Result` should be `.expect`-ed
466    expect: Flag,
467    /// Whether to generate `From<T>` where T is the type specified in `self_ty`.
468    from_ptr: Flag,
469    /// Whether to generate `From<*mut T>`
470    from_any_ptr: Flag,
471}
472
473impl FfiOpts {
474    /// Generate the FFI implementation for this `impl`
475    fn generate(&self, input: &ItemImpl) -> Result<TokenStream> {
476        let methods = match FfiMethods::try_from(
477            input,
478            self.self_ty
479                .as_ref()
480                .and_then(|s| parse_str::<Type>(s).ok()),
481            self.expect,
482        ) {
483            Ok(o) => o,
484            Err(e) => return Err(e),
485        };
486
487        let original_impl = self.original_impl(input, methods.original());
488        let maybe_from_ptr_impl = self.maybe_from_ptr_impl(input);
489        let maybe_from_any_ptr_impl = self.maybe_from_any_ptr_impl(input);
490        let ffi_mod = self.ffi_mod(input, methods.ffi()?);
491
492        Ok(quote! {
493            #original_impl
494
495            #maybe_from_ptr_impl
496
497            #maybe_from_any_ptr_impl
498
499            #ffi_mod
500
501        }
502        .into())
503    }
504
505    fn input_name(&self, input: &ItemImpl) -> TokenStream2 {
506        let Type::Path(p) = &*input.self_ty else {
507            abort!(input, "Self type must be path");
508        };
509
510        let Some(last) = p.path.segments.last() else {
511            abort!(input, "Self type must have segments");
512        };
513
514        match last.arguments {
515            PathArguments::None => {
516                let name = &input.self_ty;
517                quote!(#name)
518            }
519            PathArguments::AngleBracketed(_) => {
520                let last_ident = &last.ident;
521                let mut segments = p.path.segments.iter().cloned().collect::<Vec<_>>();
522                segments.pop();
523                let segments = segments.iter().map(|s| quote!(#s)).collect::<Vec<_>>();
524                quote!(#(#segments)::*#last_ident)
525            }
526            PathArguments::Parenthesized(_) => {
527                abort!(input, "Parenthesized path arguments are not allowed here")
528            }
529        }
530    }
531
532    fn self_type_generics(&self, input: &ItemImpl) -> Vec<GenericArgument> {
533        let Type::Path(p) = &*input.self_ty else {
534            abort!(input, "Self type must be path");
535        };
536
537        let Some(last) = p.path.segments.last() else {
538            abort!(input, "Self type must have segments");
539        };
540
541        match last.arguments {
542            PathArguments::None => {
543                vec![]
544            }
545            PathArguments::AngleBracketed(ref a) => a.args.clone().into_iter().collect::<Vec<_>>(),
546            PathArguments::Parenthesized(_) => {
547                abort!(input, "Parenthesized path arguments are not allowed here")
548            }
549        }
550    }
551
552    fn original_impl(&self, input: &ItemImpl, original: TokenStream2) -> TokenStream2 {
553        // Extract the trait component of the `impl X (for Y) {` item. We need this in addition to the
554        // generics below because we re-emit the original implementation.
555        let maybe_trait = input.trait_.as_ref().map(|(not, path, f)| {
556            let maybe_not = not.map(|not| quote!(#not)).unwrap_or_default();
557            quote!(#maybe_not #path #f)
558        });
559
560        let impl_generics = &input.generics.params.iter().collect::<Vec<_>>();
561        let where_clause = &input.generics.where_clause;
562        let input_name = self.input_name(input);
563        let self_type_generics = self.self_type_generics(input);
564
565        let maybe_impl_generics = if impl_generics.is_empty() {
566            quote!()
567        } else {
568            quote!(<#(#impl_generics),*>)
569        };
570
571        let maybe_self_type_generics = if self_type_generics.is_empty() {
572            quote!()
573        } else {
574            quote!(<#(#self_type_generics),*>)
575        };
576
577        quote! {
578            impl #maybe_impl_generics #maybe_trait #input_name #maybe_self_type_generics #where_clause {
579                #original
580            }
581        }
582    }
583
584    fn maybe_from_ptr_impl(&self, input: &ItemImpl) -> TokenStream2 {
585        let input_name = self.input_name(input);
586        let self_type_generics = self.self_type_generics(input);
587        let impl_generics_from = self
588            .self_type_generics(input)
589            .iter()
590            .map(|g| quote!(#g))
591            .collect::<Vec<_>>();
592        self.from_ptr.is_present()
593            .then_some(
594                self
595                .self_ty
596                .as_ref()
597                .and_then(|st| {
598                    parse_str(st).ok().map(|stp: Type| {
599                        quote! {
600                            impl<#(#impl_generics_from),*> From<#stp> for &'static mut #input_name<#(#self_type_generics),*> {
601                                fn from(value: #stp) -> Self {
602                                    let ptr: *mut #input_name <#(#self_type_generics),*>= value as *mut #input_name <#(#self_type_generics),*>;
603                                    unsafe { &mut *ptr }
604                                }
605                            }
606
607                            impl<#(#impl_generics_from),*> From<#stp> for &'static #input_name <#(#self_type_generics),*> {
608                                fn from(value: #stp) -> Self {
609                                    let ptr: *mut #input_name <#(#self_type_generics),*> = value as *mut #input_name <#(#self_type_generics),*>;
610                                    unsafe { &*ptr }
611                                }
612                            }
613                        }
614                    })
615                })
616            )
617            .flatten()
618            .unwrap_or_default()
619    }
620
621    fn maybe_from_any_ptr_impl(&self, input: &ItemImpl) -> TokenStream2 {
622        let input_name = self.input_name(input);
623        let self_type_generics = self.self_type_generics(input);
624        let impl_generics_from = self
625            .self_type_generics(input)
626            .iter()
627            .map(|g| quote!(#g))
628            .collect::<Vec<_>>();
629        self.from_any_ptr.is_present().then_some(quote! {
630            impl<#(#impl_generics_from),*> From<*mut T> for &'static mut #input_name<#(#self_type_generics),*> {
631                fn from(value: *mut T) -> Self {
632                    let ptr: *mut #input_name <#(#self_type_generics),*>= value as *mut #input_name <#(#self_type_generics),*>;
633                    unsafe { &mut *ptr }
634                }
635            }
636
637            impl<#(#impl_generics_from),*> From<*mut T> for &'static #input_name<#(#self_type_generics),*> {
638                fn from(value: *mut T) -> Self {
639                    let ptr: *mut #input_name <#(#self_type_generics),*> = value as *mut #input_name <#(#self_type_generics),*>;
640                    unsafe { &*ptr }
641                }
642            }
643
644            impl<#(#impl_generics_from),*> From<*const T> for &'static #input_name<#(#self_type_generics),*> {
645                fn from(value: *const T) -> Self {
646                    let ptr: *const #input_name <#(#self_type_generics),*> = value as *const #input_name <#(#self_type_generics),*>;
647                    unsafe { &*ptr }
648                }
649            }
650        }).unwrap_or_default()
651    }
652
653    fn ffi_mod(&self, input: &ItemImpl, ffi: TokenStream2) -> TokenStream2 {
654        let visibility = if let Some(ref visibility) = self.visibility {
655            match parse_str(visibility) {
656                Ok(visibility) => visibility,
657                Err(e) => Error::from(e).write_errors(),
658            }
659        } else {
660            // NOTE: Defaults to public visibility, because this is typically requred for FFI
661            quote!(pub)
662        };
663
664        let name = self.module_name(input);
665
666        quote! {
667            #visibility mod #name {
668                use super::*;
669                #ffi
670            }
671        }
672    }
673
674    fn module_name(&self, input: &ItemImpl) -> TokenStream2 {
675        if let Some(name) = self.name.as_ref().map(|n| {
676            let name = format_ident!("{n}");
677            quote!(#name)
678        }) {
679            name
680        } else {
681            let Type::Path(path) = input.self_ty.as_ref() else {
682                abort!(input, "Implementation self type is not a path");
683            };
684
685            let Some(name) = path.path.segments.first() else {
686                abort!(path, "Path has no segments");
687            };
688
689            let ffi_mod_name = format_ident!("{}", name.ident.to_string().to_ascii_lowercase());
690
691            quote!(#ffi_mod_name)
692        }
693    }
694}
695
696#[proc_macro_attribute]
697#[proc_macro_error]
698/// Wrap an `impl` block with `#[ffi(...)]` to generate FFI functions for all methods in the `impl`
699/// block.
700///
701/// # Arguments
702///
703/// The `impl`-level `ffi` attribute accepts the following parameters:
704///
705/// * `mod_name`: The name of the module to create to contain the FFI functions.
706///   Defaults to the name of the type being implemented, converted to lowercase. For
707///   example `name = "vec3_mod"`.
708/// * `visibility`: The visibility of the module to create to contain the FFI functions.
709///   Defaults to `pub`. For example `visibility = "pub(crate)"`.
710/// * `self_ty`: The self type to use for the receiver argument for all methods.
711///   Defaults to a mut pointer to the type being implemented. For example `self_ty =
712///   "*mut std::ffi::c_void"`.
713/// * `expect`: If the method returns a `Result`, whether to call `.expect` on the
714///   result. Defaults to `false`. For example `expect`.
715/// * `from_ptr`: Whether to generate `From<T>` where T is the type specified in
716///   `self_ty`. Defaults to `false`. For example `from_ptr`. If not specified, a manual
717///   implementation must be provided.
718/// * `from_any_ptr`: Whether to generate `From<*mut T>`. Defaults to `false`. For
719///   example `from_any_ptr`. If not specified, a manual implementation must be provided.
720///
721/// For example, an impl-level attribute specifying that a public module named `my_ffi_mod`,
722/// containing FFI functions for all methods in the `Vec3` impl block, should be generated,
723/// with the receiver type `*mut std::ffi::c_void` and that methods which return a `Result`
724/// should be `.expect`-ed and a `From<*mut std::ffi::c_void>` implementation should be
725/// generated, would look like:
726///
727/// ```rust,ignore
728/// #[ffi(mod_name = "my_ffi_mod", self_ty = "*mut std::ffi::c_void", expect, from_ptr)]
729/// ```
730///
731/// The method-level `ffi` attribute accepts the following parameters:
732///
733/// * `expect`: If the method returns a `Result`, whether to call `.expect` on the
734///   result. Defaults to `false`. For example `expect`. If not specified on the `impl` level
735///   attribute, the module level attribute takes precedence.
736/// * `visibility`: The visibility of the generated FFI function. Defaults to `pub`.
737///   For example `visibility = "pub(crate)"`.
738/// * `name`: The name of the generated FFI function. Defaults to the name of the method
739///   being implemented. For example `name = "vec3_add"`.
740/// * `arg`: Can be specified multiple times. The arguments to the generated FFI function.
741///
742/// For example, a method-level attribute specifying that a public FFI function named
743/// `vec3_add` should be generated, which takes its receiver as the last argument and that
744/// methods which return a `Result` should be `.expect`-ed, would look like:
745///
746/// ```rust,ignore
747/// #[ffi(arg(), arg(), arg(), arg(self), expect, name = "vec3_add")]
748/// fn vec3_add(&mut self, x: i32, y: i32, z: i32) { /* */ }
749/// ```
750///
751/// The argument-level `arg` attribute accepts the following parameters:
752///
753/// * `self`: Whether this argument needs to be converted to the receiver type. Defaults
754///   to `false`. For example `self`.
755/// * `rest`: Whether this argument is the rest of the arguments. Defaults to `false`.
756///   After `rest` is specified, no other `arg` attributes may be specified.
757/// * `ty`: The type to convert this argument to. Defaults to the type of the argument.
758///   For example `ty = "i32"`. A valid `From` implementation must exist for this type.
759/// * `rename`: The name of the argument in the generated FFI function. Defaults to the
760///   name of the argument. For example `rename = "x"`.
761///
762/// An empty `arg()` specifies only the position of an argument. In the following example, we
763/// specify that the FFI function should receive the first three non-receiver arguments, then
764/// the receiver argument.
765///
766/// ```rust,ignore
767/// #[ffi(arg(), arg(), arg(), arg(self))]
768/// fn vec3_add(&mut self, x: i32, y: i32, z: i32) { /* */ }
769/// ```
770///
771/// This is equivalent to:
772///
773/// ```rust,ignore
774/// #[ffi(arg(rest), arg(self))]
775/// fn vec3_add(&mut self, x: i32, y: i32, z: i32) { /* */ }
776/// ```
777///
778/// Likewise:
779///
780/// ```rust,ignore
781/// #[ffi(arg(self), arg(), arg(), arg())]
782/// fn vec3_add(&mut self, x: i32, y: i32, z: i32) { /* */ }
783/// ```
784///
785/// is equivalent to:
786///
787/// ```rust,ignore
788/// #[ffi(arg(self), arg(rest))]
789/// fn vec3_add(&mut self, x: i32, y: i32, z: i32) { /* */ }
790/// ```
791///
792/// # Example
793///
794/// The simple use case, where a callback we specify is called with user data we specify.
795///
796/// ```rust
797/// use ffi::ffi;
798///
799/// extern "C" fn run_callback(
800///     callback: extern "C" fn(*mut std::ffi::c_void, i32, i32, i32) -> i32,
801///     data: *mut std::ffi::c_void,
802/// ) -> i32 {
803///     callback(data, 1, 2, 3)
804/// }
805///
806/// #[derive(Debug, Clone, PartialEq, Eq)]
807/// struct Vec3 {
808///     x: i32,
809///     y: i32,
810///     z: i32,
811/// }
812///
813/// #[ffi(from_ptr, self_ty = "*mut std::ffi::c_void")]
814/// impl Vec3 {
815///     #[ffi(arg(self), arg(rest))]
816///     fn add(&mut self, x: i32, y: i32, z: i32) -> i32 {
817///         self.x += x;
818///         self.y += y;
819///         self.z += z;
820///         self.x + self.y + self.z
821///     }
822/// }
823///
824/// fn main() {
825///     let mut v = Vec3 { x: 1, y: 2, z: 3 };
826///
827///     run_callback(vec3::add, &mut v as *mut Vec3 as *mut _);
828///
829///     assert_eq!(v, Vec3 { x: 2, y: 4, z: 6 })
830/// }
831/// ```
832pub fn ffi(args: TokenStream, input: TokenStream) -> TokenStream {
833    let meta = match NestedMeta::parse_meta_list(args.into()) {
834        Ok(o) => o,
835        Err(e) => return TokenStream::from(Error::from(e).write_errors()),
836    };
837
838    let options = match FfiOpts::from_list(&meta) {
839        Ok(o) => o,
840        Err(e) => return TokenStream::from(e.write_errors()),
841    };
842
843    let impl_item = parse_macro_input!(input as ItemImpl);
844
845    options
846        .generate(&impl_item)
847        .unwrap_or_else(|e| TokenStream::from(e.write_errors()))
848}