bevy/crates/bevy_reflect/Cargo.toml

52 lines
1.4 KiB
TOML
Raw Normal View History

2020-11-28 00:39:59 +00:00
[package]
name = "bevy_reflect"
version = "0.12.0-dev"
edition = "2021"
2020-11-28 00:39:59 +00:00
description = "Dynamically interact with rust types"
homepage = "https://bevyengine.org"
repository = "https://github.com/bevyengine/bevy"
Relicense Bevy under the dual MIT or Apache-2.0 license (#2509) This relicenses Bevy under the dual MIT or Apache-2.0 license. For rationale, see #2373. * Changes the LICENSE file to describe the dual license. Moved the MIT license to docs/LICENSE-MIT. Added the Apache-2.0 license to docs/LICENSE-APACHE. I opted for this approach over dumping both license files at the root (the more common approach) for a number of reasons: * Github links to the "first" license file (LICENSE-APACHE) in its license links (you can see this in the wgpu and rust-analyzer repos). People clicking these links might erroneously think that the apache license is the only option. Rust and Amethyst both use COPYRIGHT or COPYING files to solve this problem, but this creates more file noise (if you do everything at the root) and the naming feels way less intuitive. * People have a reflex to look for a LICENSE file. By providing a single license file at the root, we make it easy for them to understand our licensing approach. * I like keeping the root clean and noise free * There is precedent for putting the apache and mit license text in sub folders (amethyst) * Removed the `Copyright (c) 2020 Carter Anderson` copyright notice from the MIT license. I don't care about this attribution, it might make license compliance more difficult in some cases, and it didn't properly attribute other contributors. We shoudn't replace it with something like "Copyright (c) 2021 Bevy Contributors" because "Bevy Contributors" is not a legal entity. Instead, we just won't include the copyright line (which has precedent ... Rust also uses this approach). * Updates crates to use the new "MIT OR Apache-2.0" license value * Removes the old legion-transform license file from bevy_transform. bevy_transform has been its own, fully custom implementation for a long time and that license no longer applies. * Added a License section to the main readme * Updated our Bevy Plugin licensing guidelines. As a follow-up we should update the website to properly describe the new license. Closes #2373
2021-07-23 21:11:51 +00:00
license = "MIT OR Apache-2.0"
2020-11-28 00:39:59 +00:00
keywords = ["bevy"]
readme = "README.md"
[features]
default = []
# When enabled, provides Bevy-related reflection implementations
bevy = ["glam", "smallvec", "bevy_math", "smol_str"]
# When enabled, allows documentation comments to be accessed via reflection
documentation = ["bevy_reflect_derive/documentation"]
2020-11-28 00:39:59 +00:00
[dependencies]
# bevy
bevy_math = { path = "../bevy_math", version = "0.12.0-dev", features = [
"serialize",
], optional = true }
bevy_reflect_derive = { path = "bevy_reflect_derive", version = "0.12.0-dev" }
bevy_utils = { path = "../bevy_utils", version = "0.12.0-dev" }
bevy_ptr = { path = "../bevy_ptr", version = "0.12.0-dev" }
2020-11-28 00:39:59 +00:00
# other
erased-serde = "0.3"
downcast-rs = "1.2"
parking_lot = "0.12.1"
2020-11-28 00:39:59 +00:00
thiserror = "1.0"
bevy_reflect: Add statically available type info for reflected types (#4042) # Objective > Resolves #4504 It can be helpful to have access to type information without requiring an instance of that type. Especially for `Reflect`, a lot of the gathered type information is known at compile-time and should not necessarily require an instance. ## Solution Created a dedicated `TypeInfo` enum to store static type information. All types that derive `Reflect` now also implement the newly created `Typed` trait: ```rust pub trait Typed: Reflect { fn type_info() -> &'static TypeInfo; } ``` > Note: This trait was made separate from `Reflect` due to `Sized` restrictions. If you only have access to a `dyn Reflect`, just call `.get_type_info()` on it. This new trait method on `Reflect` should return the same value as if you had called it statically. If all you have is a `TypeId` or type name, you can get the `TypeInfo` directly from the registry using the `TypeRegistry::get_type_info` method (assuming it was registered). ### Usage Below is an example of working with `TypeInfo`. As you can see, we don't have to generate an instance of `MyTupleStruct` in order to get this information. ```rust #[derive(Reflect)] struct MyTupleStruct(usize, i32, MyStruct); let info = MyTupleStruct::type_info(); if let TypeInfo::TupleStruct(info) = info { assert!(info.is::<MyTupleStruct>()); assert_eq!(std::any::type_name::<MyTupleStruct>(), info.type_name()); assert!(info.field_at(1).unwrap().is::<i32>()); } else { panic!("Expected `TypeInfo::TupleStruct`"); } ``` ### Manual Implementations It's not recommended to manually implement `Typed` yourself, but if you must, you can use the `TypeInfoCell` to automatically create and manage the static `TypeInfo`s for you (which is very helpful for blanket/generic impls): ```rust use bevy_reflect::{Reflect, TupleStructInfo, TypeInfo, UnnamedField}; use bevy_reflect::utility::TypeInfoCell; struct Foo<T: Reflect>(T); impl<T: Reflect> Typed for Foo<T> { fn type_info() -> &'static TypeInfo { static CELL: TypeInfoCell = TypeInfoCell::generic(); CELL.get_or_insert::<Self, _>(|| { let fields = [UnnamedField::new::<T>()]; let info = TupleStructInfo::new::<Self>(&fields); TypeInfo::TupleStruct(info) }) } } ``` ## Benefits One major benefit is that this opens the door to other serialization methods. Since we can get all the type info at compile time, we can know how to properly deserialize something like: ```rust #[derive(Reflect)] struct MyType { foo: usize, bar: Vec<String> } // RON to be deserialized: ( type: "my_crate::MyType", // <- We now know how to deserialize the rest of this object value: { // "foo" is a value type matching "usize" "foo": 123, // "bar" is a list type matching "Vec<String>" with item type "String" "bar": ["a", "b", "c"] } ) ``` Not only is this more compact, but it has better compatibility (we can change the type of `"foo"` to `i32` without having to update our serialized data). Of course, serialization/deserialization strategies like this may need to be discussed and fully considered before possibly making a change. However, we will be better equipped to do that now that we can access type information right from the registry. ## Discussion Some items to discuss: 1. Duplication. There's a bit of overlap with the existing traits/structs since they require an instance of the type while the type info structs do not (for example, `Struct::field_at(&self, index: usize)` and `StructInfo::field_at(&self, index: usize)`, though only `StructInfo` is accessible without an instance object). Is this okay, or do we want to handle it in another way? 2. Should `TypeInfo::Dynamic` be removed? Since the dynamic types don't have type information available at runtime, we could consider them `TypeInfo::Value`s (or just even just `TypeInfo::Struct`). The intention with `TypeInfo::Dynamic` was to keep the distinction from these dynamic types and actual structs/values since users might incorrectly believe the methods of the dynamic type's info struct would map to some contained data (which isn't possible statically). 4. General usefulness of this change, including missing/unnecessary parts. 5. Possible changes to the scene format? (One possible issue with changing it like in the example above might be that we'd have to be careful when handling generic or trait object types.) ## Compile Tests I ran a few tests to compare compile times (as suggested [here](https://github.com/bevyengine/bevy/pull/4042#discussion_r876408143)). I toggled `Reflect` and `FromReflect` derive macros using `cfg_attr` for both this PR (aa5178e7736a6f8252e10e543e52722107649d3f) and main (c309acd4322b1c3b2089e247a2d28b938eb7b56d). <details> <summary>See More</summary> The test project included 250 of the following structs (as well as a few other structs): ```rust #[derive(Default)] #[cfg_attr(feature = "reflect", derive(Reflect))] #[cfg_attr(feature = "from_reflect", derive(FromReflect))] pub struct Big001 { inventory: Inventory, foo: usize, bar: String, baz: ItemDescriptor, items: [Item; 20], hello: Option<String>, world: HashMap<i32, String>, okay: (isize, usize, /* wesize */), nope: ((String, String), (f32, f32)), blah: Cow<'static, str>, } ``` > I don't know if the compiler can optimize all these duplicate structs away, but I think it's fine either way. We're comparing times, not finding the absolute worst-case time. I only ran each build 3 times using `cargo build --timings` (thank you @devil-ira), each of which were preceeded by a `cargo clean --package bevy_reflect_compile_test`. Here are the times I got: | Test | Test 1 | Test 2 | Test 3 | Average | | -------------------------------- | ------ | ------ | ------ | ------- | | Main | 1.7s | 3.1s | 1.9s | 2.33s | | Main + `Reflect` | 8.3s | 8.6s | 8.1s | 8.33s | | Main + `Reflect` + `FromReflect` | 11.6s | 11.8s | 13.8s | 12.4s | | PR | 3.5s | 1.8s | 1.9s | 2.4s | | PR + `Reflect` | 9.2s | 8.8s | 9.3s | 9.1s | | PR + `Reflect` + `FromReflect` | 12.9s | 12.3s | 12.5s | 12.56s | </details> --- ## Future Work Even though everything could probably be made `const`, we unfortunately can't. This is because `TypeId::of::<T>()` is not yet `const` (see https://github.com/rust-lang/rust/issues/77125). When it does get stabilized, it would probably be worth coming back and making things `const`. Co-authored-by: MrGVSV <49806985+MrGVSV@users.noreply.github.com>
2022-06-09 21:18:15 +00:00
once_cell = "1.11"
serde = "1"
smallvec = { version = "1.6", features = [
"serde",
"union",
"const_generics",
], optional = true }
glam = { version = "0.24.1", features = ["serde"], optional = true }
smol_str = { version = "0.2.0", optional = true }
2020-11-28 00:39:59 +00:00
[dev-dependencies]
ron = "0.8.0"
bevy_reflect: Binary formats (#6140) # Objective Closes #5934 Currently it is not possible to de/serialize data to non-self-describing formats using reflection. ## Solution Add support for non-self-describing de/serialization using reflection. This allows us to use binary formatters, like [`postcard`](https://crates.io/crates/postcard): ```rust #[derive(Reflect, FromReflect, Debug, PartialEq)] struct Foo { data: String } let mut registry = TypeRegistry::new(); registry.register::<Foo>(); let input = Foo { data: "Hello world!".to_string() }; // === Serialize! === // let serializer = ReflectSerializer::new(&input, &registry); let bytes: Vec<u8> = postcard::to_allocvec(&serializer).unwrap(); println!("{:?}", bytes); // Output: [129, 217, 61, 98, ...] // === Deserialize! === // let deserializer = UntypedReflectDeserializer::new(&registry); let dynamic_output = deserializer .deserialize(&mut postcard::Deserializer::from_bytes(&bytes)) .unwrap(); let output = <Foo as FromReflect>::from_reflect(dynamic_output.as_ref()).unwrap(); assert_eq!(expected, output); // OK! ``` #### Crates Tested - ~~[`rmp-serde`](https://crates.io/crates/rmp-serde)~~ Apparently, this _is_ self-describing - ~~[`bincode` v2.0.0-rc.1](https://crates.io/crates/bincode/2.0.0-rc.1) (using [this PR](https://github.com/bincode-org/bincode/pull/586))~~ This actually works for the latest release (v1.3.3) of [`bincode`](https://crates.io/crates/bincode) as well. You just need to be sure to use fixed-int encoding. - [`postcard`](https://crates.io/crates/postcard) ## Future Work Ideally, we would refactor the `serde` module, but I don't think I'll do that in this PR so as to keep the diff relatively small (and to avoid any painful rebases). This should probably be done once this is merged, though. Some areas we could improve with a refactor: * Split deserialization logic across multiple files * Consolidate helper functions/structs * Make the logic more DRY --- ## Changelog - Add support for non-self-describing de/serialization using reflection. Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
2022-11-04 02:22:54 +00:00
rmp-serde = "1.1"
bincode = "1.3"
[[example]]
name = "reflect_docs"
path = "examples/reflect_docs.rs"
required-features = ["documentation"]