Skip to content

Commit

Permalink
Improve reflection hygiene
Browse files Browse the repository at this point in the history
Wrap impl-only macros inside unnamed constants.
  • Loading branch information
MrGVSV committed Oct 21, 2023
1 parent f10dd3a commit 973a147
Showing 1 changed file with 63 additions and 24 deletions.
87 changes: 63 additions & 24 deletions crates/bevy_reflect/bevy_reflect_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,15 +244,20 @@ pub fn derive_from_reflect(input: TokenStream) -> TokenStream {
Err(err) => return err.into_compile_error().into(),
};

match derive_data {
let from_reflect_impl = match derive_data {
ReflectDerive::Struct(struct_data) | ReflectDerive::UnitStruct(struct_data) => {
from_reflect::impl_struct(&struct_data)
}
ReflectDerive::TupleStruct(struct_data) => from_reflect::impl_tuple_struct(&struct_data),
ReflectDerive::Enum(meta) => from_reflect::impl_enum(&meta),
ReflectDerive::Value(meta) => from_reflect::impl_value(&meta),
}
.into()
};

TokenStream::from(quote! {
const _: () = {
#from_reflect_impl
};
})
}

/// Derives the `TypePath` trait, providing a stable alternative to [`std::any::type_name`].
Expand All @@ -278,21 +283,31 @@ pub fn derive_type_path(input: TokenStream) -> TokenStream {
Err(err) => return err.into_compile_error().into(),
};

impls::impl_type_path(
let type_path_impl = impls::impl_type_path(
derive_data.meta(),
// Use `WhereClauseOptions::new_value` here so we don't enforce reflection bounds
&WhereClauseOptions::new_value(derive_data.meta()),
)
.into()
);

TokenStream::from(quote! {
const _: () = {
#type_path_impl
};
})
}

// From https://github.com/randomPoison/type-uuid
#[proc_macro_derive(TypeUuid, attributes(uuid))]
pub fn derive_type_uuid(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
type_uuid::type_uuid_derive(input)
.unwrap_or_else(syn::Error::into_compile_error)
.into()
let uuid_impl =
type_uuid::type_uuid_derive(input).unwrap_or_else(syn::Error::into_compile_error);

TokenStream::from(quote! {
const _: () = {
#uuid_impl
};
})
}

/// A macro that automatically generates type data for traits, which their implementors can then register.
Expand Down Expand Up @@ -404,8 +419,10 @@ pub fn impl_reflect_value(input: TokenStream) -> TokenStream {
let from_reflect_impl = from_reflect::impl_value(&meta);

TokenStream::from(quote! {
#reflect_impls
#from_reflect_impl
const _: () = {
#reflect_impls
#from_reflect_impl
};
})
}

Expand Down Expand Up @@ -449,7 +466,7 @@ pub fn impl_reflect_struct(input: TokenStream) -> TokenStream {
Err(err) => return err.into_compile_error().into(),
};

match derive_data {
let output = match derive_data {
ReflectDerive::Struct(struct_data) => {
if !struct_data.meta().type_path().has_custom_path() {
return syn::Error::new(
Expand All @@ -463,27 +480,30 @@ pub fn impl_reflect_struct(input: TokenStream) -> TokenStream {
let impl_struct = impls::impl_struct(&struct_data);
let impl_from_struct = from_reflect::impl_struct(&struct_data);

TokenStream::from(quote! {
quote! {
#impl_struct
#impl_from_struct
})
}
}
ReflectDerive::TupleStruct(..) => syn::Error::new(
ast.span(),
"impl_reflect_struct does not support tuple structs",
)
.into_compile_error()
.into(),
.into_compile_error(),
ReflectDerive::UnitStruct(..) => syn::Error::new(
ast.span(),
"impl_reflect_struct does not support unit structs",
)
.into_compile_error()
.into(),
.into_compile_error(),
_ => syn::Error::new(ast.span(), "impl_reflect_struct only supports structs")
.into_compile_error()
.into(),
}
.into_compile_error(),
};

TokenStream::from(quote! {
const _: () = {
#output
};
})
}

/// A macro used to generate a `FromReflect` trait implementation for the given type.
Expand Down Expand Up @@ -524,7 +544,14 @@ pub fn impl_from_reflect_value(input: TokenStream) -> TokenStream {
}
};

from_reflect::impl_value(&ReflectMeta::new(type_path, def.traits.unwrap_or_default())).into()
let from_reflect_impl =
from_reflect::impl_value(&ReflectMeta::new(type_path, def.traits.unwrap_or_default()));

TokenStream::from(quote! {
const _: () = {
#from_reflect_impl
};
})
}

/// A replacement for [deriving `TypePath`] for use on foreign types.
Expand Down Expand Up @@ -586,12 +613,24 @@ pub fn impl_type_path(input: TokenStream) -> TokenStream {

let meta = ReflectMeta::new(type_path, ReflectTraits::default());

impls::impl_type_path(&meta, &WhereClauseOptions::new_value(&meta)).into()
let type_path_impl = impls::impl_type_path(&meta, &WhereClauseOptions::new_value(&meta));

TokenStream::from(quote! {
const _: () = {
#type_path_impl
};
})
}

/// Derives `TypeUuid` for the given type. This is used internally to implement `TypeUuid` on foreign types, such as those in the std. This macro should be used in the format of `<[Generic Params]> [Type (Path)], [Uuid (String Literal)]`.
#[proc_macro]
pub fn impl_type_uuid(input: TokenStream) -> TokenStream {
let def = parse_macro_input!(input as type_uuid::TypeUuidDef);
type_uuid::gen_impl_type_uuid(def).into()
let uuid_impl = type_uuid::gen_impl_type_uuid(def);

TokenStream::from(quote! {
const _: () = {
#uuid_impl
};
})
}

0 comments on commit 973a147

Please sign in to comment.