Derive Macro bevy_reflect_derive::Reflect
source · #[derive(Reflect)]
{
// Attributes available to this derive:
#[reflect]
#[reflect_value]
#[type_path]
#[type_name]
}
Expand description
The main derive macro used by bevy_reflect
for deriving its Reflect
trait.
This macro can be used on all structs and enums (unions are not supported).
It will automatically generate implementations for Reflect
, Typed
, GetTypeRegistration
, and FromReflect
.
And, depending on the item’s structure, will either implement Struct
, TupleStruct
, or Enum
.
See the FromReflect
derive macro for more information on how to customize the FromReflect
implementation.
Container Attributes
This macro comes with some helper attributes that can be added to the container item in order to provide additional functionality or alter the generated implementations.
In addition to those listed, this macro can also use the attributes for TypePath
derives.
#[reflect(Ident)]
The #[reflect(Ident)]
attribute is used to add type data registrations to the GetTypeRegistration
implementation corresponding to the given identifier, prepended by Reflect
.
For example, #[reflect(Foo, Bar)]
would add two registrations:
one for ReflectFoo
and another for ReflectBar
.
This assumes these types are indeed in-scope wherever this macro is called.
This is often used with traits that have been marked by the #[reflect_trait]
macro in order to register the type’s implementation of that trait.
Default Registrations
The following types are automatically registered when deriving Reflect
:
ReflectFromReflect
(unless opting out ofFromReflect
)SerializationData
ReflectFromPtr
Special Identifiers
There are a few “special” identifiers that work a bit differently:
#[reflect(Debug)]
will force the implementation ofReflect::reflect_debug
to rely on the type’sDebug
implementation. A custom implementation may be provided using#[reflect(Debug(my_debug_func))]
wheremy_debug_func
is the path to a function matching the signature:(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result
.#[reflect(PartialEq)]
will force the implementation ofReflect::reflect_partial_eq
to rely on the type’sPartialEq
implementation. A custom implementation may be provided using#[reflect(PartialEq(my_partial_eq_func))]
wheremy_partial_eq_func
is the path to a function matching the signature:(&self, value: &dyn #bevy_reflect_path::Reflect) -> bool
.#[reflect(Hash)]
will force the implementation ofReflect::reflect_hash
to rely on the type’sHash
implementation. A custom implementation may be provided using#[reflect(Hash(my_hash_func))]
wheremy_hash_func
is the path to a function matching the signature:(&self) -> u64
.#[reflect(Default)]
will register theReflectDefault
type data as normal. However, it will also affect how certain other operations are performed in order to improve performance and/or robustness. An example of where this is used is in theFromReflect
derive macro, where adding this attribute will cause theFromReflect
implementation to create a base value using itsDefault
implementation avoiding issues with ignored fields (for structs and tuple structs only).
#[reflect_value]
The #[reflect_value]
attribute (which may also take the form #[reflect_value(Ident)]
),
denotes that the item should implement Reflect
as though it were a base value type.
This means that it will forgo implementing Struct
, TupleStruct
, or Enum
.
Furthermore, it requires that the type implements Clone
.
If planning to serialize this type using the reflection serializers,
then the Serialize
and Deserialize
traits will need to be implemented and registered as well.
#[reflect(from_reflect = false)]
This attribute will opt-out of the default FromReflect
implementation.
This is useful for when a type can’t or shouldn’t implement FromReflect
,
or if a manual implementation is desired.
Note that in the latter case, ReflectFromReflect
will no longer be automatically registered.
#[reflect(type_path = false)]
This attribute will opt-out of the default TypePath
implementation.
This is useful for when a type can’t or shouldn’t implement TypePath
,
or if a manual implementation is desired.
#[reflect(no_field_bounds)]
This attribute will opt-out of the default trait bounds added to all field types for the generated reflection trait impls.
Normally, all fields will have the bounds TypePath
, and either FromReflect
or Reflect
depending on if #[reflect(from_reflect = false)]
is used.
However, this might not always be desirable, and so this attribute may be used to remove those bounds.
Example
If a type is recursive the default bounds will cause an overflow error when building:
#[derive(Reflect)] // ERROR: overflow evaluating the requirement `Foo: FromReflect`
struct Foo {
foo: Vec<Foo>,
}
// Generates a where clause like:
// impl bevy_reflect::Reflect for Foo
// where
// Self: Any + Send + Sync,
// Vec<Foo>: FromReflect + TypePath,
In this case, Foo
is given the bounds Vec<Foo>: FromReflect + TypePath
,
which requires that Foo
implements FromReflect
,
which requires that Vec<Foo>
implements FromReflect
,
and so on, resulting in the error.
To fix this, we can add #[reflect(no_field_bounds)]
to Foo
to remove the bounds on Vec<Foo>
:
#[derive(Reflect)]
#[reflect(no_field_bounds)]
struct Foo {
foo: Vec<Foo>,
}
// Generates a where clause like:
// impl bevy_reflect::Reflect for Foo
// where
// Self: Any + Send + Sync,
#[reflect(where T: Trait, U::Assoc: Trait, ...)]
This attribute can be used to add additional bounds to the generated reflection trait impls.
This is useful for when a type needs certain bounds only applied to the reflection impls that are not otherwise automatically added by the derive macro.
Example
In the example below, we want to enforce that T::Assoc: List
is required in order for
Foo<T>
to be reflectable, but we don’t want it to prevent Foo<T>
from being used
in places where T::Assoc: List
is not required.
trait Trait {
type Assoc;
}
#[derive(Reflect)]
#[reflect(where T::Assoc: List)]
struct Foo<T: Trait> where T::Assoc: Default {
value: T::Assoc,
}
// Generates a where clause like:
//
// impl<T: Trait> bevy_reflect::Reflect for Foo<T>
// where
// Self: Any + Send + Sync,
// T::Assoc: Default,
// T: TypePath,
// T::Assoc: FromReflect + TypePath,
// T::Assoc: List,
// {/* ... */}
Field Attributes
Along with the container attributes, this macro comes with some attributes that may be applied to the contained fields themselves.
#[reflect(ignore)]
This attribute simply marks a field to be ignored by the reflection API.
This allows fields to completely opt-out of reflection,
which may be useful for maintaining invariants, keeping certain data private,
or allowing the use of types that do not implement Reflect
within the container.
#[reflect(skip_serializing)]
This works similar to #[reflect(ignore)]
, but rather than opting out of all of reflection,
it simply opts the field out of both serialization and deserialization.
This can be useful when a field should be accessible via reflection, but may not make
sense in a serialized form, such as computed data.
What this does is register the SerializationData
type within the GetTypeRegistration
implementation,
which will be used by the reflection serializers to determine whether or not the field is serializable.