271 lines
8.2 KiB
Rust
271 lines
8.2 KiB
Rust
|
use quote::quote;
|
||
|
use syn::{Token, parenthesized, punctuated::Punctuated};
|
||
|
|
||
|
struct Field {
|
||
|
name: syn::Ident,
|
||
|
_eq: Token![=],
|
||
|
ty: syn::Ident,
|
||
|
}
|
||
|
|
||
|
impl syn::parse::Parse for Field {
|
||
|
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||
|
Ok(Self {
|
||
|
name: input.parse()?,
|
||
|
_eq: input.parse()?,
|
||
|
ty: input.parse()?,
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
struct SimpleStruct {
|
||
|
type_path: syn::Path,
|
||
|
pub generics: syn::Generics,
|
||
|
fields: Vec<Field>,
|
||
|
}
|
||
|
|
||
|
impl syn::parse::Parse for SimpleStruct {
|
||
|
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||
|
//let type_path = syn::Path::parse_mod_style(input)?;
|
||
|
let type_path: syn::Path = input.parse()?;
|
||
|
/* let mut generics = input.parse::<syn::Generics>()?;
|
||
|
generics.where_clause = input.parse()?; */
|
||
|
|
||
|
let mut fields = vec![];
|
||
|
|
||
|
// parse fields if a comma is found
|
||
|
if input.peek(Token![,]) {
|
||
|
let _: Token![,] = input.parse()?;
|
||
|
let ident: syn::Ident = input.parse()?;
|
||
|
let ident_str = ident.to_string();
|
||
|
|
||
|
match ident_str.as_str() {
|
||
|
"fields" => {
|
||
|
let content;
|
||
|
let _parens: syn::token::Paren = parenthesized!(content in input);
|
||
|
|
||
|
let f: Punctuated<Field, Token![,]> = content.parse_terminated(Field::parse, Token![,])?;
|
||
|
fields = f.into_iter().collect();
|
||
|
},
|
||
|
_ => return Err(syn::Error::new(ident.span(), "Unknown macro command, expected `fields`")),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Ok(Self {
|
||
|
type_path,
|
||
|
generics: syn::Generics::default(),
|
||
|
fields,
|
||
|
})
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
fn gen_match_field_name_arm(simple: &SimpleStruct, default: &proc_macro2::TokenStream, arm_gen: fn(field: &Field) -> proc_macro2::TokenStream) -> proc_macro2::TokenStream {
|
||
|
let field_arms_iter = simple.fields.iter().map(|f| {
|
||
|
let fname = &f.name;
|
||
|
let arm = arm_gen(f);
|
||
|
|
||
|
quote! {
|
||
|
stringify!(#fname) => #arm
|
||
|
}
|
||
|
});
|
||
|
|
||
|
quote! {
|
||
|
match name {
|
||
|
#(#field_arms_iter,)*
|
||
|
_ => #default,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn gen_match_field_index_arm(simple: &SimpleStruct, default: &proc_macro2::TokenStream, arm_gen: fn(field: &Field) -> proc_macro2::TokenStream) -> proc_macro2::TokenStream {
|
||
|
let field_arms_iter = simple.fields.iter().enumerate().map(|(idx, f)| {
|
||
|
let arm = arm_gen(f);
|
||
|
|
||
|
quote! {
|
||
|
#idx => #arm
|
||
|
}
|
||
|
});
|
||
|
|
||
|
quote! {
|
||
|
match idx {
|
||
|
#(#field_arms_iter,)*
|
||
|
_ => #default,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub(crate) fn impl_reflect_simple_struct(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||
|
let simple = syn::parse_macro_input!(input as SimpleStruct);
|
||
|
|
||
|
let type_path = &simple.type_path;
|
||
|
let (impl_generics, ty_generics, where_clause) = simple.generics.split_for_impl();
|
||
|
// 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("::")
|
||
|
}; */
|
||
|
|
||
|
let borrow_fn = |field: &Field| {
|
||
|
let name = &field.name;
|
||
|
quote! {
|
||
|
Some(&self.#name)
|
||
|
}
|
||
|
};
|
||
|
|
||
|
let borrow_mut_fn = |field: &Field| {
|
||
|
let name = &field.name;
|
||
|
quote! {
|
||
|
Some(&mut self.#name)
|
||
|
}
|
||
|
};
|
||
|
|
||
|
let none_default = quote!(None);
|
||
|
let false_return_default = quote!( { return false; });
|
||
|
|
||
|
let field_count = simple.fields.len();
|
||
|
|
||
|
let field_fn = gen_match_field_name_arm(&simple, &none_default, borrow_fn);
|
||
|
let field_mut_fn = gen_match_field_name_arm(&simple, &none_default, borrow_mut_fn);
|
||
|
let field_at_fn = gen_match_field_index_arm(&simple, &none_default, borrow_fn);
|
||
|
let field_at_mut_fn = gen_match_field_index_arm(&simple, &none_default, borrow_mut_fn);
|
||
|
let field_name_at_fn = gen_match_field_index_arm(&simple, &none_default, |f| {
|
||
|
let name = &f.name;
|
||
|
quote! {
|
||
|
Some(stringify!(#name))
|
||
|
}
|
||
|
});
|
||
|
|
||
|
let set_field_arm = |f: &Field| {
|
||
|
let name = &f.name;
|
||
|
let ty = &f.ty;
|
||
|
quote! {
|
||
|
self.#name = any_val.downcast_ref::<#ty>()
|
||
|
.expect(&format!("Cannot set struct's field of {} type to the provided type of {}", stringify!(#name), val.name()))
|
||
|
.clone() //Some(&#mut_tkn self.#field_ident)
|
||
|
}
|
||
|
};
|
||
|
|
||
|
let set_field_fn = gen_match_field_name_arm(&simple, &false_return_default, set_field_arm);
|
||
|
let set_field_at_fn = gen_match_field_index_arm(&simple, &false_return_default, set_field_arm);
|
||
|
|
||
|
let get_field_ty_arm = |f: &Field| {
|
||
|
let fty = &f.ty;
|
||
|
quote! {
|
||
|
Some(stringify!(#fty))
|
||
|
}
|
||
|
};
|
||
|
let field_type_fn = gen_match_field_name_arm(&simple, &none_default, get_field_ty_arm);
|
||
|
let field_type_at_fn = gen_match_field_index_arm(&simple, &none_default, get_field_ty_arm);
|
||
|
|
||
|
proc_macro::TokenStream::from(quote! {
|
||
|
impl #impl_generics lyra_engine::reflect::Reflect for #type_path #ty_generics #where_clause {
|
||
|
fn name(&self) -> ::std::string::String {
|
||
|
stringify!(#type_path).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
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl #impl_generics lyra_engine::reflect::Struct for #type_path #ty_generics #where_clause {
|
||
|
fn field(&self, name: &str) -> Option<&dyn Reflect> {
|
||
|
#field_fn
|
||
|
}
|
||
|
|
||
|
fn field_mut(&mut self, name: &str) -> Option<&mut dyn Reflect> {
|
||
|
#field_mut_fn
|
||
|
}
|
||
|
|
||
|
fn fields_len(&self) -> usize {
|
||
|
#field_count
|
||
|
}
|
||
|
|
||
|
fn field_at(&self, idx: usize) -> Option<&dyn Reflect> {
|
||
|
#field_at_fn
|
||
|
}
|
||
|
|
||
|
fn field_at_mut(&mut self, idx: usize) -> Option<&mut dyn Reflect> {
|
||
|
#field_at_mut_fn
|
||
|
}
|
||
|
|
||
|
fn field_name_at(&self, idx: usize) -> Option<&str> {
|
||
|
#field_name_at_fn
|
||
|
}
|
||
|
|
||
|
fn set_field(&mut self, name: &str, val: &dyn Reflect) -> bool {
|
||
|
let any_val = val.as_any();
|
||
|
|
||
|
#set_field_fn
|
||
|
|
||
|
true
|
||
|
}
|
||
|
|
||
|
fn set_field_at(&mut self, idx: usize, val: &dyn Reflect) -> bool {
|
||
|
let any_val = val.as_any();
|
||
|
|
||
|
#set_field_at_fn
|
||
|
|
||
|
true
|
||
|
}
|
||
|
|
||
|
fn field_type(&self, name: &str) -> Option<&'static str> {
|
||
|
#field_type_fn
|
||
|
}
|
||
|
|
||
|
fn field_type_at(&self, idx: usize) -> Option<&'static str> {
|
||
|
#field_type_at_fn
|
||
|
}
|
||
|
|
||
|
fn method(&self, name: &str) -> Option<&Method> {
|
||
|
unimplemented!()
|
||
|
}
|
||
|
|
||
|
fn method_at(&self, idx: usize) -> Option<&Method> {
|
||
|
unimplemented!()
|
||
|
}
|
||
|
|
||
|
fn methods_len(&self) -> usize {
|
||
|
unimplemented!()
|
||
|
}
|
||
|
}
|
||
|
})
|
||
|
}
|