use proc_macro2::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Data, DeriveInput, Error, Fields, ItemTrait};
#[proc_macro_derive(Pointee)]
pub fn pointee_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput);
proc_macro::TokenStream::from(derive_pointee_impl(&input))
}
fn derive_pointee_impl(input: &DeriveInput) -> TokenStream {
let ident = &input.ident;
let last_field_ty = match input.data {
Data::Struct(ref data) => match data.fields {
Fields::Named(ref fields) => {
if let Some(result) = fields.named.last() {
&result.ty
} else {
return Error::new(ident.span(), "dynamically sized structs must contain at least one field").to_compile_error();
}
},
Fields::Unnamed(ref fields) => {
if let Some(result) = fields.unnamed.last() {
&result.ty
} else {
return Error::new(ident.span(), "dynamically sized structs must contain at least one field").to_compile_error();
}
},
Fields::Unit => return Error::new(ident.span(), "unit structs cannot be dynamically sized").to_compile_error(),
},
Data::Enum(_) => return Error::new(ident.span(), "enums cannot be dynamically sized").to_compile_error(),
Data::Union(_) => return Error::new(ident.span(), "unions cannot be dynamically sized").to_compile_error(),
};
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
quote! {
const _: () = {
use ptr_meta::Pointee;
impl #impl_generics Pointee for #ident #ty_generics #where_clause
where
#last_field_ty: Pointee,
{
type Metadata = <#last_field_ty as Pointee>::Metadata;
}
};
}
}
#[proc_macro_attribute]
pub fn pointee(
_attr: proc_macro::TokenStream,
item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
let input = parse_macro_input!(item as ItemTrait);
let ident = &input.ident;
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
let result = quote! {
#input
const _: () = {
use ptr_meta::{DynMetadata, Pointee};
impl #impl_generics Pointee for (dyn #ident #ty_generics #where_clause + '_) {
type Metadata = DynMetadata<Self>;
}
};
};
proc_macro::TokenStream::from(result)
}