use super::*;
use quote::*;
use syn::*;
pub fn manifest_as(attr: TokenStream, input: TokenStream) -> TokenStream {
let attr_path = parse_macro_input!(attr as Path);
let input = parse_macro_input!(input as Item);
let impl_item = match &input {
Item::Impl(impl_item) => impl_item,
_ => return TokenStream::from(quote! {
::core::compile_error!("The #[manifest_as] attribute can only be used on trait implementations");
}),
};
let trait_path = match &impl_item.trait_ {
Some((_, path, _)) => path.clone(),
None => return TokenStream::from(quote! {
::core::compile_error!("The #[manifest_as] attribute can only be used on trait implementations");
}),
};
let core_path = utils::core_path_attr(&impl_item.attrs);
let assert_trait_equality = assert_trait_equality(&attr_path, &trait_path);
let implementing_type = &impl_item.self_ty;
let registration_implementation = quote! {
#core_path::inventory::submit! {
#core_path::manifest::ManifestableRegistration::<Box<dyn #trait_path>> {
type_id_fn: || ::std::any::TypeId::of::<#implementing_type>(),
qualifier_fn: || {
use #core_path::manifest::Qualify;
#implementing_type::qualifier()
},
default_fn: || {
use ::std::default::Default;
Box::new(#implementing_type::default())
},
encode_fn: |v, encoder| {
let force_downcasted: &#implementing_type = unsafe {
let (data, _vtable): (*const (), *const ()) = ::std::mem::transmute(v.as_ref());
::std::mem::transmute(data)
};
encoder.delegate_encoding(force_downcasted)
},
decode_fn: |v, decoder| -> Result<(), Box<dyn ::std::error::Error>> {
let force_downcasted: &mut #implementing_type = unsafe {
let (data, _vtable): (*const (), *const ()) = ::std::mem::transmute(v.as_ref());
::std::mem::transmute(data)
};
decoder.delegate_decoding(force_downcasted)?;
Ok(())
},
encompass_fn: |v, visitor| {
let force_downcasted: &#implementing_type = unsafe {
let (data, _vtable): (*const (), *const ()) = ::std::mem::transmute(v.as_ref());
::std::mem::transmute(data)
};
use #core_path::encompass::Encompass;
force_downcasted.encompass(visitor)
},
inspect_fn: |v, ui_context, ui| {
let force_downcasted: &mut #implementing_type = unsafe {
let (data, _vtable): (*const (), *const ()) = ::std::mem::transmute(v.as_ref());
::std::mem::transmute(data)
};
use #core_path::inspect::Inspect;
force_downcasted.inspect(ui_context, ui);
},
debug_fn: |v, formatter| {
let force_downcasted: &#implementing_type = unsafe {
let (data, _vtable): (*const (), *const ()) = ::std::mem::transmute(v.as_ref());
::std::mem::transmute(data)
};
use ::std::fmt::Debug;
force_downcasted.fmt(formatter)
},
}
}
};
let full_implementation = quote! {
#impl_item
#assert_trait_equality
#registration_implementation
};
full_implementation.into()
}
pub fn assert_trait_equality(first: &Path, second: &Path) -> TokenStream2 {
quote! {
const _: () = {
use std::marker::PhantomData;
pub struct AssertSameTrait<T: ?Sized> {
phantom: PhantomData<T>,
}
let _: AssertSameTrait<dyn #first> = AssertSameTrait::<dyn #second> { phantom: PhantomData };
};
}
}