Skip to main content

miniextendr_macros/
trait_signature.rs

1//! Infer inherited argument types from a concrete method item, not copied paths.
2
3use proc_macro2::{Span, TokenStream};
4use quote::{format_ident, quote};
5
6pub(crate) fn argument_ident(name: &syn::Ident) -> syn::Ident {
7    match ::quote::__private::IdentFragmentAdapter(&crate::naming::unraw(name)) {
    arg =>
        ::quote::__private::mk_ident(&::alloc::__export::must_use({
                        ::alloc::fmt::format(format_args!("__mx_type_{0}", arg))
                    }),
            ::quote::__private::Option::Some::<::quote::__private::Span>(Span::mixed_site())),
}format_ident!(
8        "__mx_type_{}",
9        crate::naming::unraw(name),
10        span = Span::mixed_site()
11    )
12}
13
14/// This local generic function only inspects a callable's signature. It never
15/// calls it, constructs an argument, or adds conversion bounds to the trait.
16pub(crate) fn setup(
17    inputs: &syn::punctuated::Punctuated<syn::FnArg, ::syn::token::Commasyn::Token![,]>,
18    receiver: bool,
19    callable: &TokenStream,
20) -> TokenStream {
21    let names: Vec<_> = inputs
22        .iter()
23        .filter_map(|arg| match arg {
24            syn::FnArg::Typed(arg) => match arg.pat.as_ref() {
25                syn::Pat::Ident(name) => Some(argument_ident(&name.ident)),
26                _ => None,
27            },
28            syn::FnArg::Receiver(_) => None,
29        })
30        .collect();
31    if names.is_empty() {
32        return TokenStream::new();
33    }
34    let args: Vec<_> = (0..names.len() + usize::from(receiver))
35        .map(|i| ::quote::__private::mk_ident(&::alloc::__export::must_use({
                ::alloc::fmt::format(format_args!("__MxArg{0}", i))
            }),
    ::quote::__private::Option::Some::<::quote::__private::Span>(Span::mixed_site()))format_ident!("__MxArg{i}", span = Span::mixed_site()))
36        .collect();
37    let output = syn::Ident::new("__MxOutput", Span::mixed_site());
38    let helper = syn::Ident::new("__mx_argument_types", Span::mixed_site());
39    let receiver_slot = receiver.then(|| {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_underscore(&mut _s);
    ::quote::__private::push_comma(&mut _s);
    _s
}quote!(_,));
40    {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "let");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::ToTokens::to_tokens(&receiver_slot, &mut _s);
            {
                use ::quote::__private::ext::*;
                let has_iter = ::quote::__private::HasIterator::<false>;
                #[allow(unused_mut)]
                let (mut names, i) = names.quote_into_iter();
                let has_iter = has_iter | i;
                <_ as
                        ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                while true {
                    let names =
                        match names.next() {
                            Some(_x) => ::quote::__private::RepInterp(_x),
                            None => break,
                        };
                    ::quote::ToTokens::to_tokens(&names, &mut _s);
                    ::quote::__private::push_comma(&mut _s);
                }
            }
            _s
        });
    ::quote::__private::push_eq(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "fn");
            ::quote::ToTokens::to_tokens(&helper, &mut _s);
            ::quote::__private::push_lt(&mut _s);
            ::quote::ToTokens::to_tokens(&output, &mut _s);
            ::quote::__private::push_comma(&mut _s);
            {
                use ::quote::__private::ext::*;
                let mut _first = true;
                let has_iter = ::quote::__private::HasIterator::<false>;
                #[allow(unused_mut)]
                let (mut args, i) = args.quote_into_iter();
                let has_iter = has_iter | i;
                <_ as
                        ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                while true {
                    let args =
                        match args.next() {
                            Some(_x) => ::quote::__private::RepInterp(_x),
                            None => break,
                        };
                    if !_first { ::quote::__private::push_comma(&mut _s); }
                    _first = false;
                    ::quote::ToTokens::to_tokens(&args, &mut _s);
                }
            }
            ::quote::__private::push_gt(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_underscore(&mut _s);
                    ::quote::__private::push_colon(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "impl");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "core");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "ops");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "FnOnce");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            {
                                use ::quote::__private::ext::*;
                                let mut _first = true;
                                let has_iter = ::quote::__private::HasIterator::<false>;
                                #[allow(unused_mut)]
                                let (mut args, i) = args.quote_into_iter();
                                let has_iter = has_iter | i;
                                <_ as
                                        ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                                while true {
                                    let args =
                                        match args.next() {
                                            Some(_x) => ::quote::__private::RepInterp(_x),
                                            None => break,
                                        };
                                    if !_first { ::quote::__private::push_comma(&mut _s); }
                                    _first = false;
                                    ::quote::ToTokens::to_tokens(&args, &mut _s);
                                }
                            }
                            _s
                        });
                    ::quote::__private::push_rarrow(&mut _s);
                    ::quote::ToTokens::to_tokens(&output, &mut _s);
                    ::quote::__private::push_comma(&mut _s);
                    _s
                });
            ::quote::__private::push_rarrow(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    {
                        use ::quote::__private::ext::*;
                        let has_iter = ::quote::__private::HasIterator::<false>;
                        #[allow(unused_mut)]
                        let (mut args, i) = args.quote_into_iter();
                        let has_iter = has_iter | i;
                        <_ as
                                ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                        while true {
                            let args =
                                match args.next() {
                                    Some(_x) => ::quote::__private::RepInterp(_x),
                                    None => break,
                                };
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "miniextendr_api");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "trait_abi");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "signature");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "Argument");
                            ::quote::__private::push_lt(&mut _s);
                            ::quote::ToTokens::to_tokens(&args, &mut _s);
                            ::quote::__private::push_gt(&mut _s);
                            ::quote::__private::push_comma(&mut _s);
                        }
                    }
                    _s
                });
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            {
                                use ::quote::__private::ext::*;
                                let has_iter = ::quote::__private::HasIterator::<false>;
                                #[allow(unused_mut)]
                                let (mut args, i) = args.quote_into_iter();
                                let has_iter = has_iter | i;
                                <_ as
                                        ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                                while true {
                                    let args =
                                        match args.next() {
                                            Some(_x) => ::quote::__private::RepInterp(_x),
                                            None => break,
                                        };
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "miniextendr_api");
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "trait_abi");
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "signature");
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "Argument");
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_lt(&mut _s);
                                    ::quote::ToTokens::to_tokens(&args, &mut _s);
                                    ::quote::__private::push_gt(&mut _s);
                                    ::quote::__private::push_colon2(&mut _s);
                                    ::quote::__private::push_ident(&mut _s, "NEW");
                                    ::quote::__private::push_comma(&mut _s);
                                }
                            }
                            _s
                        });
                    _s
                });
            ::quote::ToTokens::to_tokens(&helper, &mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::ToTokens::to_tokens(&callable, &mut _s);
                    _s
                });
            _s
        });
    ::quote::__private::push_semi(&mut _s);
    _s
}quote! {
41        let (#receiver_slot #(#names,)*) = {
42            fn #helper<#output, #(#args),*>(
43                _: impl ::core::ops::FnOnce(#(#args),*) -> #output,
44            ) -> (#(::miniextendr_api::trait_abi::signature::Argument<#args>,)*) {
45                (#(::miniextendr_api::trait_abi::signature::Argument::<#args>::NEW,)*)
46            }
47            #helper(#callable)
48        };
49    }
50}
51
52/// Unsafe or foreign-ABI methods are not FnOnce items. A never-called closure
53/// presents their argument types to the same inference helper.
54pub(crate) fn callable(sig: &syn::Signature, item: TokenStream) -> TokenStream {
55    if sig.unsafety.is_none() && sig.abi.is_none() {
56        return item;
57    }
58    let args: Vec<_> = (0..sig.inputs.len())
59        .map(|i| ::quote::__private::mk_ident(&::alloc::__export::must_use({
                ::alloc::fmt::format(format_args!("__mx_value{0}", i))
            }),
    ::quote::__private::Option::Some::<::quote::__private::Span>(Span::mixed_site()))format_ident!("__mx_value{i}", span = Span::mixed_site()))
60        .collect();
61    let call = {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&item, &mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            {
                use ::quote::__private::ext::*;
                let mut _first = true;
                let has_iter = ::quote::__private::HasIterator::<false>;
                #[allow(unused_mut)]
                let (mut args, i) = args.quote_into_iter();
                let has_iter = has_iter | i;
                <_ as
                        ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                while true {
                    let args =
                        match args.next() {
                            Some(_x) => ::quote::__private::RepInterp(_x),
                            None => break,
                        };
                    if !_first { ::quote::__private::push_comma(&mut _s); }
                    _first = false;
                    ::quote::ToTokens::to_tokens(&args, &mut _s);
                }
            }
            _s
        });
    _s
}quote! { #item(#(#args),*) };
62    let call = if sig.unsafety.is_some() {
63        {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "unsafe");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::ToTokens::to_tokens(&call, &mut _s);
            _s
        });
    _s
}quote! { unsafe { #call } }
64    } else {
65        call
66    };
67    {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_or(&mut _s);
    {
        use ::quote::__private::ext::*;
        let mut _first = true;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut args, i) = args.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let args =
                match args.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            if !_first { ::quote::__private::push_comma(&mut _s); }
            _first = false;
            ::quote::ToTokens::to_tokens(&args, &mut _s);
        }
    }
    ::quote::__private::push_or(&mut _s);
    ::quote::ToTokens::to_tokens(&call, &mut _s);
    _s
}quote! { |#(#args),*| #call }
68}