Skip to main content

miniextendr_macros/
trait_receiver.rs

1//! Explicit owner-bearing trait receivers, rewritten for stable Rust.
2
3use proc_macro2::TokenStream;
4use quote::quote;
5
6#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for OwnerReceiver { }
#[automatically_derived]
impl ::core::clone::Clone for OwnerReceiver {
    #[inline]
    fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for OwnerReceiver { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for OwnerReceiver {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                OwnerReceiver::Shared => "Shared",
                OwnerReceiver::Mutable => "Mutable",
            })
    }
}Debug, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for OwnerReceiver { }
#[automatically_derived]
impl ::core::cmp::PartialEq for OwnerReceiver {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        ::core::intrinsics::discriminant_value(self) ==
            ::core::intrinsics::discriminant_value(other)
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for OwnerReceiver { }Eq)]
7pub(crate) enum OwnerReceiver {
8    Shared,
9    Mutable,
10}
11
12impl OwnerReceiver {
13    pub(crate) fn type_path(self) -> TokenStream {
14        match self {
15            Self::Shared => {
    let mut _s = ::quote::__private::TokenStream::new();
    ::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, "ExternalPtrRef");
    _s
}quote!(::miniextendr_api::ExternalPtrRef),
16            Self::Mutable => {
    let mut _s = ::quote::__private::TokenStream::new();
    ::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, "ExternalPtrMut");
    _s
}quote!(::miniextendr_api::ExternalPtrMut),
17        }
18    }
19}
20
21pub(crate) fn owner_receiver(sig: &syn::Signature) -> Option<OwnerReceiver> {
22    let receiver = sig.receiver()?;
23    // Only an explicit `self: Type` receiver can name a handle.
24    receiver.colon_token?;
25    let syn::Type::Path(path) = receiver.ty.as_ref() else {
26        return None;
27    };
28    if path.qself.is_some() {
29        return None;
30    }
31    let segment = path.path.segments.last()?;
32    let kind = match segment.ident.to_string().as_str() {
33        "ExternalPtrRef" => OwnerReceiver::Shared,
34        "ExternalPtrMut" => OwnerReceiver::Mutable,
35        _ => return None,
36    };
37    let syn::PathArguments::AngleBracketed(args) = &segment.arguments else {
38        return None;
39    };
40    let mut types = args.args.iter().filter_map(|arg| match arg {
41        syn::GenericArgument::Type(ty) => Some(ty),
42        _ => None,
43    });
44    match (types.next(), types.next()) {
45        (Some(syn::Type::Path(ty)), None) if ty.qself.is_none() && ty.path.is_ident("Self") => {
46            Some(kind)
47        }
48        _ => None,
49    }
50}
51
52pub(crate) fn is_mut(sig: &syn::Signature) -> bool {
53    match owner_receiver(sig) {
54        Some(OwnerReceiver::Mutable) => true,
55        Some(OwnerReceiver::Shared) => false,
56        None => sig
57            .receiver()
58            .is_some_and(|receiver| match receiver.ty.as_ref() {
59                syn::Type::Reference(reference) => reference.mutability.is_some(),
60                _ => receiver.mutability.is_some(),
61            }),
62    }
63}
64
65/// Keep the source signature for wrapper metadata; rewrite only the emitted
66/// Rust trait/impl. The associated function takes its borrowed handle by value.
67pub(crate) fn rewrite(sig: &mut syn::Signature, body: Option<&mut syn::Block>) {
68    if owner_receiver(sig).is_none() {
69        return;
70    }
71    let receiver = sig.receiver().expect("owner receiver");
72    let ty = receiver.ty.clone();
73    let mutability = receiver.mutability;
74    let receiver_ident = syn::Ident::new("__miniextendr_self", proc_macro2::Span::mixed_site());
75    sig.inputs[0] = ::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::ToTokens::to_tokens(&receiver_ident, &mut _s);
        ::quote::__private::push_colon(&mut _s);
        ::quote::ToTokens::to_tokens(&ty, &mut _s);
        _s
    })syn::parse_quote!(#receiver_ident: #ty);
76    if let Some(body) = body {
77        sig.inputs[0] = ::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::ToTokens::to_tokens(&mutability, &mut _s);
        ::quote::ToTokens::to_tokens(&receiver_ident, &mut _s);
        ::quote::__private::push_colon(&mut _s);
        ::quote::ToTokens::to_tokens(&ty, &mut _s);
        _s
    })syn::parse_quote!(#mutability #receiver_ident: #ty);
78        crate::receiver_body::rewrite(body, &receiver_ident);
79    }
80}