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

121 lines
3.8 KiB
Rust
Raw Normal View History

2023-12-30 23:55:05 +00:00
use std::slice::Split;
use proc_macro::TokenStream;
use quote::{quote, ToTokens};
use syn::{Generics, parse::ParseBuffer, Path, Attribute, GenericParam, parse_quote, parse_macro_input, DeriveInput, TypeParamBound};
mod enum_derive;
use enum_derive::*;
mod struct_derive;
use struct_derive::*;
pub(crate) struct ReflectDef {
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 mut generics = input.parse::<Generics>()?;
generics.where_clause = input.parse()?;
Ok(Self {
type_path,
generics,
attributes,
})
}
}
#[proc_macro_derive(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.clone().into_token_stream();
let name_id = &reflect.type_path.segments.last().unwrap().ident;
let name = name_id.span().source_text().unwrap();
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 {
#name.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 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
}