Path: blob/main/examples/reflection/custom_attributes.rs
6849 views
//! Demonstrates how to register and access custom attributes on reflected types.12use bevy::reflect::{Reflect, TypeInfo, Typed};3use std::{any::TypeId, ops::RangeInclusive};45fn main() {6// Bevy supports statically registering custom attribute data on reflected types,7// which can then be accessed at runtime via the type's `TypeInfo`.8// Attributes are registered using the `#[reflect(@...)]` syntax,9// where the `...` is any expression that resolves to a value which implements `Reflect`.10// Note that these attributes are stored based on their type:11// if two attributes have the same type, the second one will overwrite the first.1213// Here is an example of registering custom attributes on a type:14#[derive(Reflect)]15struct Slider {16#[reflect(@RangeInclusive::<f32>::new(0.0, 1.0))]17// Alternatively, we could have used the `0.0..=1.0` syntax,18// but remember to ensure the type is the one you want!19#[reflect(@0.0..=1.0_f32)]20value: f32,21}2223// Now, we can access the custom attributes at runtime:24let TypeInfo::Struct(type_info) = Slider::type_info() else {25panic!("expected struct");26};2728let field = type_info.field("value").unwrap();2930let range = field.get_attribute::<RangeInclusive<f32>>().unwrap();31assert_eq!(*range, 0.0..=1.0);3233// And remember that our attributes can be any type that implements `Reflect`:34#[derive(Reflect)]35struct Required;3637#[derive(Reflect, PartialEq, Debug)]38struct Tooltip(String);3940impl Tooltip {41fn new(text: &str) -> Self {42Self(text.to_string())43}44}4546#[derive(Reflect)]47#[reflect(@Required, @Tooltip::new("An ID is required!"))]48struct Id(u8);4950let TypeInfo::TupleStruct(type_info) = Id::type_info() else {51panic!("expected struct");52};5354// We can check if an attribute simply exists on our type:55assert!(type_info.has_attribute::<Required>());5657// We can also get attribute data dynamically:58let some_type_id = TypeId::of::<Tooltip>();5960let tooltip: &dyn Reflect = type_info.get_attribute_by_id(some_type_id).unwrap();61assert_eq!(62tooltip.downcast_ref::<Tooltip>(),63Some(&Tooltip::new("An ID is required!"))64);6566// And again, attributes of the same type will overwrite each other:67#[derive(Reflect)]68enum Status {69// This will result in `false` being stored:70#[reflect(@true)]71#[reflect(@false)]72Disabled,73// This will result in `true` being stored:74#[reflect(@false)]75#[reflect(@true)]76Enabled,77}7879let TypeInfo::Enum(type_info) = Status::type_info() else {80panic!("expected enum");81};8283let disabled = type_info.variant("Disabled").unwrap();84assert!(!disabled.get_attribute::<bool>().unwrap());8586let enabled = type_info.variant("Enabled").unwrap();87assert!(enabled.get_attribute::<bool>().unwrap());88}899091