Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/examples/reflection/custom_attributes.rs
6849 views
1
//! Demonstrates how to register and access custom attributes on reflected types.
2
3
use bevy::reflect::{Reflect, TypeInfo, Typed};
4
use std::{any::TypeId, ops::RangeInclusive};
5
6
fn main() {
7
// Bevy supports statically registering custom attribute data on reflected types,
8
// which can then be accessed at runtime via the type's `TypeInfo`.
9
// Attributes are registered using the `#[reflect(@...)]` syntax,
10
// where the `...` is any expression that resolves to a value which implements `Reflect`.
11
// Note that these attributes are stored based on their type:
12
// if two attributes have the same type, the second one will overwrite the first.
13
14
// Here is an example of registering custom attributes on a type:
15
#[derive(Reflect)]
16
struct Slider {
17
#[reflect(@RangeInclusive::<f32>::new(0.0, 1.0))]
18
// Alternatively, we could have used the `0.0..=1.0` syntax,
19
// but remember to ensure the type is the one you want!
20
#[reflect(@0.0..=1.0_f32)]
21
value: f32,
22
}
23
24
// Now, we can access the custom attributes at runtime:
25
let TypeInfo::Struct(type_info) = Slider::type_info() else {
26
panic!("expected struct");
27
};
28
29
let field = type_info.field("value").unwrap();
30
31
let range = field.get_attribute::<RangeInclusive<f32>>().unwrap();
32
assert_eq!(*range, 0.0..=1.0);
33
34
// And remember that our attributes can be any type that implements `Reflect`:
35
#[derive(Reflect)]
36
struct Required;
37
38
#[derive(Reflect, PartialEq, Debug)]
39
struct Tooltip(String);
40
41
impl Tooltip {
42
fn new(text: &str) -> Self {
43
Self(text.to_string())
44
}
45
}
46
47
#[derive(Reflect)]
48
#[reflect(@Required, @Tooltip::new("An ID is required!"))]
49
struct Id(u8);
50
51
let TypeInfo::TupleStruct(type_info) = Id::type_info() else {
52
panic!("expected struct");
53
};
54
55
// We can check if an attribute simply exists on our type:
56
assert!(type_info.has_attribute::<Required>());
57
58
// We can also get attribute data dynamically:
59
let some_type_id = TypeId::of::<Tooltip>();
60
61
let tooltip: &dyn Reflect = type_info.get_attribute_by_id(some_type_id).unwrap();
62
assert_eq!(
63
tooltip.downcast_ref::<Tooltip>(),
64
Some(&Tooltip::new("An ID is required!"))
65
);
66
67
// And again, attributes of the same type will overwrite each other:
68
#[derive(Reflect)]
69
enum Status {
70
// This will result in `false` being stored:
71
#[reflect(@true)]
72
#[reflect(@false)]
73
Disabled,
74
// This will result in `true` being stored:
75
#[reflect(@false)]
76
#[reflect(@true)]
77
Enabled,
78
}
79
80
let TypeInfo::Enum(type_info) = Status::type_info() else {
81
panic!("expected enum");
82
};
83
84
let disabled = type_info.variant("Disabled").unwrap();
85
assert!(!disabled.get_attribute::<bool>().unwrap());
86
87
let enabled = type_info.variant("Enabled").unwrap();
88
assert!(enabled.get_attribute::<bool>().unwrap());
89
}
90
91