121 lines
3.8 KiB
Rust
121 lines
3.8 KiB
Rust
|
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
|
||
|
}
|