lyra-engine/lyra-reflect/lyra-reflect-derive/src/lib.rs

181 lines
5.6 KiB
Rust
Raw Normal View History

2023-12-30 23:55:05 +00:00
use proc_macro::TokenStream;
use proc_macro2::Ident;
2024-03-09 05:34:50 +00:00
use quote::quote;
2024-01-06 20:52:12 +00:00
use syn::{Generics, Path, Attribute, GenericParam, parse_macro_input, DeriveInput, TypeParamBound};
2023-12-30 23:55:05 +00:00
mod enum_derive;
2024-01-06 20:52:12 +00:00
#[allow(unused_imports)]
2023-12-30 23:55:05 +00:00
use enum_derive::*;
mod struct_derive;
2024-01-06 20:52:12 +00:00
#[allow(unused_imports)]
2023-12-30 23:55:05 +00:00
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<ReflectAttribute>);
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<syn::Attribute>) -> Result<Self, syn::Error> {
let s: Result<Vec<ReflectAttribute>, _> = v.iter().filter_map(|att| match &att.meta {
syn::Meta::Path(_) => None,
syn::Meta::List(l) => {
Some(syn::parse::<ReflectAttribute>(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<Self> {
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"))
}
}
}
2024-01-06 20:52:12 +00:00
#[allow(dead_code)]
2023-12-30 23:55:05 +00:00
pub(crate) struct ReflectDef {
//pub ident: Ident,
2023-12-30 23:55:05 +00:00
pub type_path: Path,
pub generics: Generics,
pub attributes: Vec<Attribute>
}
impl syn::parse::Parse for ReflectDef {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let attributes = input.call(Attribute::parse_outer)?;
let type_path = Path::parse_mod_style(input)?;
//let ident = type_path. //type_path.require_ident()?;
2023-12-30 23:55:05 +00:00
let mut generics = input.parse::<Generics>()?;
generics.where_clause = input.parse()?;
Ok(Self {
//ident: ident.clone(),
2023-12-30 23:55:05 +00:00
type_path,
generics,
attributes,
})
}
}
#[proc_macro_derive(Reflect, attributes(reflect))]
2023-12-30 23:55:05 +00:00
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<String> = type_path.segments.iter()
.map(|segment| segment.ident.to_string())
.collect();
idents.join("::")
};
2023-12-30 23:55:05 +00:00
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()
2023-12-30 23:55:05 +00:00
}
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 apply(&mut self, val: &dyn lyra_engine::reflect::Reflect) {
let val = val.as_any().downcast_ref::<Self>()
.expect("The type of `val` is not the same as `self`");
*self = val.clone();
}
fn clone_inner(&self) -> Box<dyn lyra_engine::reflect::Reflect> {
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<TypeParamBound>) -> 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)
2023-12-30 23:55:05 +00:00
}