bevy/examples/reflection/custom_attributes.rs
Clar Fon efda7f3f9c
Simpler lint fixes: makes ci lints work but disables a lint for now (#15376)
Takes the first two commits from #15375 and adds suggestions from this
comment:
https://github.com/bevyengine/bevy/pull/15375#issuecomment-2366968300

See #15375 for more reasoning/motivation.

## Rebasing (rerunning)

```rust
git switch simpler-lint-fixes
git reset --hard main
cargo fmt --all -- --unstable-features --config normalize_comments=true,imports_granularity=Crate
cargo fmt --all
git add --update
git commit --message "rustfmt"
cargo clippy --workspace --all-targets --all-features --fix
cargo fmt --all -- --unstable-features --config normalize_comments=true,imports_granularity=Crate
cargo fmt --all
git add --update
git commit --message "clippy"
git cherry-pick e6c0b94f6795222310fb812fa5c4512661fc7887
```
2024-09-24 11:42:59 +00:00

89 lines
2.9 KiB
Rust

//! Demonstrates how to register and access custom attributes on reflected types.
use bevy::reflect::{Reflect, TypeInfo, Typed};
use std::{any::TypeId, ops::RangeInclusive};
fn main() {
// Bevy supports statically registering custom attribute data on reflected types,
// which can then be accessed at runtime via the type's `TypeInfo`.
// Attributes are registered using the `#[reflect(@...)]` syntax,
// where the `...` is any expression that resolves to a value which implements `Reflect`.
// Note that these attributes are stored based on their type:
// if two attributes have the same type, the second one will overwrite the first.
// Here is an example of registering custom attributes on a type:
#[derive(Reflect)]
struct Slider {
#[reflect(@RangeInclusive::<f32>::new(0.0, 1.0))]
// Alternatively, we could have used the `0.0..=1.0` syntax,
// but remember to ensure the type is the one you want!
#[reflect(@0.0..=1.0_f32)]
value: f32,
}
// Now, we can access the custom attributes at runtime:
let TypeInfo::Struct(type_info) = Slider::type_info() else {
panic!("expected struct");
};
let field = type_info.field("value").unwrap();
let range = field.get_attribute::<RangeInclusive<f32>>().unwrap();
assert_eq!(*range, 0.0..=1.0);
// And remember that our attributes can be any type that implements `Reflect`:
#[derive(Reflect)]
struct Required;
#[derive(Reflect, PartialEq, Debug)]
struct Tooltip(String);
impl Tooltip {
fn new(text: &str) -> Self {
Self(text.to_string())
}
}
#[derive(Reflect)]
#[reflect(@Required, @Tooltip::new("An ID is required!"))]
struct Id(u8);
let TypeInfo::TupleStruct(type_info) = Id::type_info() else {
panic!("expected struct");
};
// We can check if an attribute simply exists on our type:
assert!(type_info.has_attribute::<Required>());
// We can also get attribute data dynamically:
let some_type_id = TypeId::of::<Tooltip>();
let tooltip: &dyn Reflect = type_info.get_attribute_by_id(some_type_id).unwrap();
assert_eq!(
tooltip.downcast_ref::<Tooltip>(),
Some(&Tooltip::new("An ID is required!"))
);
// And again, attributes of the same type will overwrite each other:
#[derive(Reflect)]
enum Status {
// This will result in `false` being stored:
#[reflect(@true)]
#[reflect(@false)]
Disabled,
// This will result in `true` being stored:
#[reflect(@false)]
#[reflect(@true)]
Enabled,
}
let TypeInfo::Enum(type_info) = Status::type_info() else {
panic!("expected enum");
};
let disabled = type_info.variant("Disabled").unwrap();
assert!(!disabled.get_attribute::<bool>().unwrap());
let enabled = type_info.variant("Enabled").unwrap();
assert!(enabled.get_attribute::<bool>().unwrap());
}