extern-trait-impl 0.4.3

Proc-macro implementation for extern-trait
Documentation
use proc_macro2::{Span, TokenStream};
use quote::{quote, quote_spanned};
use syn::{ItemImpl, Result, spanned::Spanned};

use crate::args::ImplArgs;

pub fn expand(args: ImplArgs, input: ItemImpl) -> Result<TokenStream> {
    let Some((_, trait_, _)) = &input.trait_ else {
        return Err(syn::Error::new(Span::call_site(), "expected a trait impl"));
    };

    if !input.generics.params.is_empty() {
        return Err(syn::Error::new_spanned(
            input.generics,
            "#[extern_trait] impls may not have generics",
        ));
    }

    if let Some(where_clause) = &input.generics.where_clause {
        return Err(syn::Error::new_spanned(
            where_clause,
            "#[extern_trait] impls may not have a where clause",
        ));
    }

    let extern_trait = args.extern_trait;
    let ty = &input.self_ty;

    let assert = quote_spanned! {ty.span()=>
        const _: () = {
            assert!(
                ::core::mem::size_of::<#ty>() <= ::core::mem::size_of::<#extern_trait::Repr>(),
                concat!(stringify!(#ty), " is too large to be used with #[extern_trait]")
            );
        };
    };

    Ok(quote! {
        #input

        #assert

        #trait_!(#trait_: #ty);
    })
}