use proc_macro::TokenStream; use proc_macro2::Ident; use quote::quote; use syn::{parse_macro_input, Attribute, DeriveInput, GenericParam, Generics, Path, TypeParamBound}; mod enum_derive; #[allow(unused_imports)] use enum_derive::*; mod struct_derive; #[allow(unused_imports)] use struct_derive::*; mod struct_macro; /* #[proc_macro_attribute(attributes(reflect))] pub fn reflect(_attr: proc_macro::TokenStream, item: proc_macro::TokenStream) -> proc_macro::TokenStream { item } */ pub(crate) struct FieldAttributes(Vec); impl FieldAttributes { /// Searches for a usage of the 'reflect' attribute and returns a list of the /// things used in the usage. pub fn from_vec(v: &Vec) -> Result { let s: Result, _> = v.iter().filter_map(|att| match &att.meta { syn::Meta::Path(_) => None, syn::Meta::List(l) => { Some(syn::parse::(l.tokens.clone().into())) } syn::Meta::NameValue(_) => None }).collect(); Ok(Self(s?)) } pub fn has_skip(&self) -> bool { self.0.iter().any(|a| *a == ReflectAttribute::Skip) } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) enum ReflectAttribute { Skip } impl syn::parse::Parse for ReflectAttribute { fn parse(input: syn::parse::ParseStream) -> syn::Result { let ident: Ident = input.parse()?; let ident_str = ident.to_string().to_lowercase(); match ident_str.as_str() { "skip" => Ok(Self::Skip), _ => Err(syn::Error::new(ident.span(), "Unknown reflect attribute flag")) } } } #[allow(dead_code)] pub(crate) struct ReflectDef { //pub ident: Ident, pub type_path: Path, pub generics: Generics, pub attributes: Vec } impl syn::parse::Parse for ReflectDef { fn parse(input: syn::parse::ParseStream) -> syn::Result { let attributes = input.call(Attribute::parse_outer)?; let type_path = Path::parse_mod_style(input)?; //let ident = type_path. //type_path.require_ident()?; let mut generics = input.parse::()?; /* let f: Punctuated = input.parse_terminated(GenericParam::parse, Token![,])?; generics.params = f; */ generics.where_clause = input.parse()?; Ok(Self { //ident: ident.clone(), type_path, generics, attributes, }) } } #[proc_macro_derive(Reflect, attributes(reflect))] pub fn derive_reflect(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let input = parse_macro_input!(input as DeriveInput); let stream = match &input.data { syn::Data::Enum(e) => { enum_derive::derive_reflect_enum(&input, e) }, syn::Data::Struct(s) => { struct_derive::derive_reflect_struct(&input, s) }, //syn::Data::Union(_) => todo!(), _ => todo!() }; proc_macro::TokenStream::from(stream) } /// Implements `Reflect` for Values. `ReflectRef` and `ReflectMut` will be the `Value` /// variants, its used for simple types and primitives. #[proc_macro] pub fn impl_reflect_trait_value(input: TokenStream) -> TokenStream { let reflect = syn::parse_macro_input!(input as ReflectDef); let type_path = reflect.type_path; // convert the type path to a string. This would not create a leading separator let type_path_str = { let idents: Vec = type_path.segments.iter() .map(|segment| segment.ident.to_string()) .collect(); idents.join("::") }; let (impl_generics, ty_generics, where_clause) = reflect.generics.split_for_impl(); TokenStream::from(quote! { impl #impl_generics lyra_engine::reflect::Reflect for #type_path #ty_generics #where_clause { fn name(&self) -> ::std::string::String { #type_path_str.to_string() } fn type_id(&self) -> std::any::TypeId { std::any::TypeId::of::<#type_path #ty_generics>() } fn as_any(&self) -> &dyn std::any::Any { self } fn as_any_mut(&mut self) -> &mut dyn std::any::Any { self } fn as_boxed_any(self: Box) -> Box { self } fn apply(&mut self, val: &dyn lyra_engine::reflect::Reflect) { let val = val.as_any().downcast_ref::() .expect("The type of `val` is not the same as `self`"); *self = val.clone(); } fn clone_inner(&self) -> Box { Box::new(self.clone()) } fn reflect_ref(&self) -> lyra_engine::reflect::ReflectRef { lyra_engine::reflect::ReflectRef::Value(self) } fn reflect_mut(&mut self) -> lyra_engine::reflect::ReflectMut { lyra_engine::reflect::ReflectMut::Value(self) } fn reflect_val(&self) -> &dyn lyra_engine::reflect::Reflect { self } fn reflect_val_mut(&mut self) -> &mut dyn lyra_engine::reflect::Reflect { self } } }) } pub(crate) fn add_trait_bounds(mut generics: Generics, add_bounds: Vec) -> Generics { for param in &mut generics.params { if let GenericParam::Type(ref mut type_param) = *param { for bound in add_bounds.iter() { type_param.bounds.push(bound.clone()); } } } generics } #[proc_macro] pub fn impl_reflect_simple_struct(input: TokenStream) -> TokenStream { struct_macro::impl_reflect_simple_struct(input) }