From 1137f3aa9f95ec41f3cb307eec53817fbe530abc Mon Sep 17 00:00:00 2001 From: Aceeri Date: Sun, 18 Jun 2017 04:28:39 -0700 Subject: [PATCH] Extend component list --- .gitignore | 1 + .travis.yml | 3 +- Cargo.toml | 7 +- {specs/benches => benches}/parallel.rs | 0 {specs/benches => benches}/world.rs | 0 {specs/examples => examples}/basic.rs | 0 {specs_derive/examples => examples}/derive.rs | 14 +- {specs/examples => examples}/full.rs | 0 {specs/examples => examples}/serialize.rs | 3 +- specs/.gitignore | 7 - specs/Cargo.toml | 49 ----- specs/README.md | 107 ----------- specs_derive/Cargo.toml | 3 +- specs_derive/README.md | 136 +++++++------- specs_derive/src/component_group.rs | 175 +++++++++--------- {specs/src => src}/group.rs | 0 {specs/src => src}/join.rs | 0 {specs/src => src}/lib.rs | 1 - {specs/src => src}/storage/check.rs | 0 {specs/src => src}/storage/data.rs | 0 {specs/src => src}/storage/mod.rs | 0 {specs/src => src}/storage/ser.rs | 0 {specs/src => src}/storage/storages.rs | 0 {specs/src => src}/storage/tests.rs | 0 {specs/src => src}/world.rs | 2 - {specs/tests => tests}/tests.rs | 0 26 files changed, 164 insertions(+), 344 deletions(-) rename {specs/benches => benches}/parallel.rs (100%) rename {specs/benches => benches}/world.rs (100%) rename {specs/examples => examples}/basic.rs (100%) rename {specs_derive/examples => examples}/derive.rs (90%) rename {specs/examples => examples}/full.rs (100%) rename {specs/examples => examples}/serialize.rs (98%) delete mode 100644 specs/.gitignore delete mode 100644 specs/Cargo.toml delete mode 100644 specs/README.md rename {specs/src => src}/group.rs (100%) rename {specs/src => src}/join.rs (100%) rename {specs/src => src}/lib.rs (99%) rename {specs/src => src}/storage/check.rs (100%) rename {specs/src => src}/storage/data.rs (100%) rename {specs/src => src}/storage/mod.rs (100%) rename {specs/src => src}/storage/ser.rs (100%) rename {specs/src => src}/storage/storages.rs (100%) rename {specs/src => src}/storage/tests.rs (100%) rename {specs/src => src}/world.rs (99%) rename {specs/tests => tests}/tests.rs (100%) diff --git a/.gitignore b/.gitignore index d7ae0ff17..62d6d6dab 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # Generated by Cargo /target/ +/specs_derive/target/ Cargo.lock # Generated by mdbook diff --git a/.travis.yml b/.travis.yml index 654b5cac6..9e3ef96f0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ language: rust rust: -- nightly +- nightly-2017-06-20 +- beta - stable branches: diff --git a/Cargo.toml b/Cargo.toml index 95f127dd5..f1f857874 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,3 @@ -<<<<<<< HEAD [package] name = "specs" version = "0.9.2" @@ -50,9 +49,10 @@ common = ["futures"] serialize = ["serde", "serde_derive"] [dev-dependencies] -cgmath = { version = "0.14", features = ["eders"] } +cgmath = { version = "0.14", features = ["eders"] } rand = "0.3" serde_json = "1.0" +specs_derive = { path = "specs_derive", version = "0.1", features = ["serialize"] } [[example]] name = "basic" @@ -68,3 +68,6 @@ required-features = ["common"] name = "serialize" required-features = ["serialize"] +[[example]] +name = "derive" +required-features = ["serialize"] diff --git a/specs/benches/parallel.rs b/benches/parallel.rs similarity index 100% rename from specs/benches/parallel.rs rename to benches/parallel.rs diff --git a/specs/benches/world.rs b/benches/world.rs similarity index 100% rename from specs/benches/world.rs rename to benches/world.rs diff --git a/specs/examples/basic.rs b/examples/basic.rs similarity index 100% rename from specs/examples/basic.rs rename to examples/basic.rs diff --git a/specs_derive/examples/derive.rs b/examples/derive.rs similarity index 90% rename from specs_derive/examples/derive.rs rename to examples/derive.rs index 9ef37198f..60a16b5a3 100644 --- a/specs_derive/examples/derive.rs +++ b/examples/derive.rs @@ -6,18 +6,13 @@ extern crate specs; #[macro_use] extern crate specs_derive; -#[cfg(feature="serialize")] extern crate serde; -#[cfg(feature="serialize")] #[macro_use] extern crate serde_derive; -#[cfg(feature="serialize")] extern crate serde_json; -#[cfg(feature="serialize")] fn main() { - use specs::{Component, ComponentGroup, DeconstructedGroup, DispatcherBuilder, Entities, EntitiesRes, Join, SerializeGroup, System, ReadStorage, Split, VecStorage, WriteStorage, World, WorldDeserializer, WorldSerializer}; - use serde::{Deserialize, Serialize}; + use specs::{Component, ComponentGroup, DeconstructedGroup, DispatcherBuilder, Entities, Join, System, Split, VecStorage, WriteStorage, World, WorldDeserializer, WorldSerializer}; use serde::de::DeserializeSeed; #[derive(Debug, Serialize, Deserialize)] @@ -54,7 +49,6 @@ fn main() { #[allow(dead_code)] struct SomeGroup { #[group(serialize)] - #[group(id = "5")] field1: Comp1, #[group(serialize)] @@ -145,7 +139,7 @@ fn main() { let world_deserializer = WorldDeserializer::::new(&mut world, entity_list.as_slice()); let mut json_deserializer = serde_json::Deserializer::from_str(&serialized); - world_deserializer.deserialize(&mut json_deserializer); + let _ = world_deserializer.deserialize(&mut json_deserializer); } { @@ -188,7 +182,3 @@ fn main() { ); } -#[cfg(not(feature="serialize"))] -fn main() { - println!("Requires `serialize` flag to run"); -} diff --git a/specs/examples/full.rs b/examples/full.rs similarity index 100% rename from specs/examples/full.rs rename to examples/full.rs diff --git a/specs/examples/serialize.rs b/examples/serialize.rs similarity index 98% rename from specs/examples/serialize.rs rename to examples/serialize.rs index bfedff4fb..3feb2b2f3 100644 --- a/specs/examples/serialize.rs +++ b/examples/serialize.rs @@ -32,6 +32,7 @@ fn main() { } #[derive(ComponentGroup)] + #[allow(dead_code)] struct SerialGroup { #[group(serialize)] comp_serialize: CompSerialize, @@ -183,7 +184,7 @@ fn main() { let world_deserializer = WorldDeserializer::::new(&mut world, entity_list.as_slice()); let mut json_deserializer = serde_json::Deserializer::from_str(&serialized); - world_deserializer.deserialize(&mut json_deserializer); + let _ = world_deserializer.deserialize(&mut json_deserializer); } { diff --git a/specs/.gitignore b/specs/.gitignore deleted file mode 100644 index 99d938f8b..000000000 --- a/specs/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -# Generated by Cargo -/target/ -Cargo.lock - -# IDEs / Editor -*.iml -.idea diff --git a/specs/Cargo.toml b/specs/Cargo.toml deleted file mode 100644 index 2e851af08..000000000 --- a/specs/Cargo.toml +++ /dev/null @@ -1,49 +0,0 @@ -[package] -name = "specs" -version = "0.9.1" -description = """ -Specs is an Entity-Component System library written in Rust. -Unlike most other ECS libraries out there, it provides - -* easy parallelism -* high flexibility - * contains 5 different storages for components, which can be extended by the user - * it's types are mostly not coupled, so you can easily write some part yourself and - still use Specs - * `System`s may read from and write to components and resources, can depend on each - other and you can use barriers to force several stages in system execution -* high performance for real-world applications -""" -documentation = "https://docs.rs/specs/" -repository = "https://github.com/slide-rs/specs" -homepage = "https://slide-rs.github.io/specs-website/" -keywords = ["gamedev"] -categories = ["concurrency"] -license = "Apache-2.0" -authors = ["slide-rs hackers"] -exclude = ["bors.toml", ".travis.yml"] - -[badges] -travis-ci = { repository = "slide-rs/specs" } - -[dependencies] -atom = "0.3" -fnv = "1.0" -hibitset = "0.1.3" -mopa = "0.2" -shred = "0.4.2" -shred-derive = "0.3" -tuple_utils = "0.2" -rayon = "0.7.1" - -serde = { version = "1.0", optional = true } -serde_derive = { version = "1.0", optional = true } - -[features] -serialize = ["serde", "serde_derive"] - -[dev-dependencies] -cgmath = { version = "0.14", features = ["eders"] } -rand = "0.3" -serde_json = "1.0" -specs_derive = { path = "../specs_derive", version = "0.1", features = ["serialize"] } diff --git a/specs/README.md b/specs/README.md deleted file mode 100644 index 359c5b964..000000000 --- a/specs/README.md +++ /dev/null @@ -1,107 +0,0 @@ -# Specs - -> **S**pecs **P**arallel **ECS** - -[![Build Status][bi]][bl] [![Crates.io][ci]][cl] [![Gitter][gi]][gl] ![MIT/Apache][li] [![Docs.rs][di]][dl] - -[bi]: https://travis-ci.org/slide-rs/specs.svg?branch=master -[bl]: https://travis-ci.org/slide-rs/specs - -[ci]: https://img.shields.io/crates/v/specs.svg -[cl]: https://crates.io/crates/specs/ - -[li]: https://img.shields.io/badge/license-Apache%202.0-blue.svg - -[di]: https://docs.rs/specs/badge.svg -[dl]: https://docs.rs/specs/ - -[gi]: https://badges.gitter.im/slide-rs/specs.svg -[gl]: https://gitter.im/slide-rs/specs - -Specs is an Entity-Component System written in Rust. -Unlike most other ECS libraries out there, it provides - -* easy parallelism -* high flexibility - * contains 5 different storages for components, which can be extended by the user - * it's types are mostly not coupled, so you can easily write some part yourself and - still use Specs - * `System`s may read from and write to components and resources, can depend on each - other and you can use barriers to force several stages in system execution -* high performance for real-world applications - -## Example - -```rust -// A component contains data -// which is associated with an entity. -#[derive(Debug)] -struct Vel(f32); -#[derive(Debug)] -struct Pos(f32); - -impl Component for Vel { - type Storage = VecStorage; -} - -impl Component for Pos { - type Storage = VecStorage; -} - -struct SysA; - -impl<'a> System<'a> for SysA { - // These are the resources required for execution. - // You can also define a struct and `#[derive(SystemData)]`, - // see the `full` example. - type SystemData = (WriteStorage<'a, Pos>, ReadStorage<'a, Vel>); - - fn run(&mut self, data: Self::SystemData) { - // The `.join()` combines multiple components, - // so we only access those entities which have - // both of them. - - let (mut pos, vel) = data; - - for (pos, vel) in (&mut pos, &vel).join() { - pos.0 += vel.0; - } - } -} - -fn main() { - // The `World` is our - // container for components - // and other resources. - let mut world = World::new(); - world.register::(); - world.register::(); - - // An entity may or may not contain some component. - - world.create_entity().with(Vel(2.0)).with(Pos(0.0)).build(); - world.create_entity().with(Vel(4.0)).with(Pos(1.6)).build(); - world.create_entity().with(Vel(1.5)).with(Pos(5.4)).build(); - - // This entity does not have `Vel`, so it won't be dispatched. - world.create_entity().with(Pos(2.0)).build(); - - // This builds a dispatcher. - // The third parameter of `add` specifies - // logical dependencies on other systems. - // Since we only have one, we don't depend on anything. - // See the `full` example for dependencies. - let mut dispatcher = DispatcherBuilder::new().add(SysA, "sys_a", &[]).build(); - - // This dispatches all the systems in parallel (but blocking). - dispatcher.dispatch(&mut world.res); -} -``` - -Please look into [the examples directory](examples) for more. - -## Contribution - -Contribution is very welcome! If you didn't contribute before, just -filter for issues with "easy" label. Please note that your contributions -are assumed to be dual-licensed under Apache-2.0/MIT. diff --git a/specs_derive/Cargo.toml b/specs_derive/Cargo.toml index 2de696191..30cd7d69d 100644 --- a/specs_derive/Cargo.toml +++ b/specs_derive/Cargo.toml @@ -7,7 +7,7 @@ authors = ["Aceeri "] proc-macro = true [dependencies] -specs = { path = "../specs", version = "0.9.1" } +specs = { path = "../", version = "0.9.2" } syn = "0.11.10" quote = "0.3.15" serde = { version = "1.0", optional = true } @@ -19,3 +19,4 @@ serde_json = "1.0" [features] default = [] serialize = ["serde", "specs/serialize"] + diff --git a/specs_derive/README.md b/specs_derive/README.md index 359c5b964..fdcde3d6d 100644 --- a/specs_derive/README.md +++ b/specs_derive/README.md @@ -1,6 +1,5 @@ -# Specs -> **S**pecs **P**arallel **ECS** +# Specs Procedural Derive Macros [![Build Status][bi]][bl] [![Crates.io][ci]][cl] [![Gitter][gi]][gl] ![MIT/Apache][li] [![Docs.rs][di]][dl] @@ -18,90 +17,83 @@ [gi]: https://badges.gitter.im/slide-rs/specs.svg [gl]: https://gitter.im/slide-rs/specs -Specs is an Entity-Component System written in Rust. -Unlike most other ECS libraries out there, it provides +## Component Grouping -* easy parallelism -* high flexibility - * contains 5 different storages for components, which can be extended by the user - * it's types are mostly not coupled, so you can easily write some part yourself and - still use Specs - * `System`s may read from and write to components and resources, can depend on each - other and you can use barriers to force several stages in system execution -* high performance for real-world applications +In a couple situations you are required to perform some task on a bunch of different components, +such as serialization or registering the component into the world. Tasks like these require either +dynamic dispatch through the use of trait objects or closures, but that can make you lose performance +and prevent some compiler optimizations. However, the alternative is a lot of boilerplate and isn't +very scalable if using third party code where they also require registering components similar to the +`World`. -## Example +In these situations it is useful to use a macro to reduce that boilerplate and make it less annoying +to add new components to the program. Component groups mark a bunch of different components that +you want to have some operation perform on all of them. -```rust -// A component contains data -// which is associated with an entity. -#[derive(Debug)] -struct Vel(f32); -#[derive(Debug)] -struct Pos(f32); - -impl Component for Vel { - type Storage = VecStorage; -} - -impl Component for Pos { - type Storage = VecStorage; -} - -struct SysA; +### Usage -impl<'a> System<'a> for SysA { - // These are the resources required for execution. - // You can also define a struct and `#[derive(SystemData)]`, - // see the `full` example. - type SystemData = (WriteStorage<'a, Pos>, ReadStorage<'a, Vel>); - fn run(&mut self, data: Self::SystemData) { - // The `.join()` combines multiple components, - // so we only access those entities which have - // both of them. +Component groups use a procedural derive macro along with using attributes with the tag `group`. +Fields in the component group `struct` are by default components, alternatively they can be marked +as a subgroup using the `subgroup` attribute. Subgroups in a component group will try to behave the +same as if the components were in the parent group. The field names are also used as unique identifiers +for components in things like serialization. - let (mut pos, vel) = data; +Note: When using the `call` macro to use the component groups, it is necessary to use another method +on subgroups for subgroups to behave correctly in the `call` macro. - for (pos, vel) in (&mut pos, &vel).join() { - pos.0 += vel.0; - } - } +```rust +#[derive(ComponentGroup)] +struct ExampleGroup { + // The group defaults to just a component. + // + // The field name "component1" will be used as an + // unique identifier. + component1: Component1, + + // Component grouping comes with built in support + // for serialization and deserialization with `serde` + // usage + #[group(serialize)] + component2: Component2, + + #[group(id = "5")] + component3: Component3, } -fn main() { - // The `World` is our - // container for components - // and other resources. - let mut world = World::new(); - world.register::(); - world.register::(); +#[derive(ComponentGroup)] +struct AnotherGroup { + component4: Component4, - // An entity may or may not contain some component. + // If you need a subgroup, then you need to + // designate the fields that are subgroups. + #[group(subgroup)] + example_group: ExampleGroup, +} +``` - world.create_entity().with(Vel(2.0)).with(Pos(0.0)).build(); - world.create_entity().with(Vel(4.0)).with(Pos(1.6)).build(); - world.create_entity().with(Vel(1.5)).with(Pos(5.4)).build(); +When operated on a method, this component group will look similar to something like: +```rust +fn method() { ... } +method::(); +method::(); +method::(); +method::(); +``` - // This entity does not have `Vel`, so it won't be dispatched. - world.create_entity().with(Pos(2.0)).build(); +### Attributes - // This builds a dispatcher. - // The third parameter of `add` specifies - // logical dependencies on other systems. - // Since we only have one, we don't depend on anything. - // See the `full` example for dependencies. - let mut dispatcher = DispatcherBuilder::new().add(SysA, "sys_a", &[]).build(); +`#[group(subgroup)]` +Marks the field as a subgroup. Will attempt to behave similar to if the components nested in the subgroup +are in the parent group. - // This dispatches all the systems in parallel (but blocking). - dispatcher.dispatch(&mut world.res); -} -``` +`#[group(serialize)]` +Marks the field as a serializable component or subgroup. All fields that are marked by this should implement +`Serialize` and `Deserialize`. The field name is used as the unique identifier for serializaion. -Please look into [the examples directory](examples) for more. +`#[group(id = "...")]` +Identifies a component id other than the default `0usize`. -## Contribution +### `call` Macro -Contribution is very welcome! If you didn't contribute before, just -filter for issues with "easy" label. Please note that your contributions -are assumed to be dual-licensed under Apache-2.0/MIT. +Component groups also provide capability for external extension using the `call` macro. diff --git a/specs_derive/src/component_group.rs b/specs_derive/src/component_group.rs index c239f2fd6..6024585d5 100644 --- a/specs_derive/src/component_group.rs +++ b/specs_derive/src/component_group.rs @@ -25,17 +25,6 @@ pub fn expand_group(input: &DeriveInput) -> Result { .collect::(); let ref comp_ty = component.types(); - // Serializable components - let ref component_serialize = component.iter() - .filter(|item| item.parameter.serialize) - .collect::(); - #[allow(unused_variables)] - let ref comp_serialize_name = component_serialize.names(); - let ref comp_serialize_id = component_serialize.ids(); - let ref comp_serialize_ty = component_serialize.types(); - #[allow(unused_variables)] - let comp_serialize_ty2 = comp_serialize_ty; - // Subgroup fields let ref subgroup = items.iter() .filter(|item| item.parameter.subgroup ) @@ -68,11 +57,7 @@ pub fn expand_group(input: &DeriveInput) -> Result { fn components() -> Vec<&'static str> { #[allow(unused_mut)] let mut list = #name::local_components(); - #( - for component in #subgroup_ty::components() { - list.push(component); - } - )* + #( list.extend(#subgroup_ty::components()); )* list } fn subgroups() -> Vec<&'static str> { @@ -84,95 +69,107 @@ pub fn expand_group(input: &DeriveInput) -> Result { } }; - // Serialization methods #[cfg(feature="serialize")] - let serialize = quote! { - fn serialize_group(world: &_specs::World, serializer: S) -> Result { - let mut map = serializer.serialize_map(None)?; - #( - let storage = world.read_with_id::<#comp_serialize_ty>(#comp_serialize_id); - _serde::ser::SerializeMap::serialize_entry(&mut map, #comp_serialize_name, &storage)?; - )* - - #( #subgroup_ty::serialize_subgroup::(world, &mut map)?; )* - _serde::ser::SerializeMap::end(map) - } + let serialize = { + // Serializable components + let ref component_serialize = component.iter() + .filter(|item| item.parameter.serialize) + .collect::(); + let ref comp_serialize_name = component_serialize.names(); + let ref comp_serialize_id = component_serialize.ids(); + let ref comp_serialize_ty = component_serialize.types(); + let comp_serialize_ty2 = comp_serialize_ty; + + quote! { + fn serialize_group(world: &_specs::World, serializer: S) -> Result { + #[allow(unused_mut)] + let mut map = serializer.serialize_map(None)?; + #( + let storage = world.read_with_id::<#comp_serialize_ty>(#comp_serialize_id); + _serde::ser::SerializeMap::serialize_entry(&mut map, #comp_serialize_name, &storage)?; + )* - fn serialize_subgroup(world: &_specs::World, map: &mut S::SerializeMap) -> Result<(), S::Error> { - #( - let storage = world.read_with_id::<#comp_serialize_ty>(#comp_serialize_id); - _serde::ser::SerializeMap::serialize_entry(map, #comp_serialize_name, &storage)?; - )* - #( #subgroup_ty::serialize_subgroup::(world, map)?; )* - Ok(()) - } + #( #subgroup_ty::serialize_subgroup::(world, &mut map)?; )* + _serde::ser::SerializeMap::end(map) + } - fn deserialize_group<'de, D: _serde::Deserializer<'de>>(world: &mut _specs::World, entities: &[_specs::Entity], deserializer: D) -> Result<(), D::Error> { - use std::fmt; + fn serialize_subgroup(world: &_specs::World, map: &mut S::SerializeMap) -> Result<(), S::Error> { + #( + let storage = world.read_with_id::<#comp_serialize_ty>(#comp_serialize_id); + _serde::ser::SerializeMap::serialize_entry(map, #comp_serialize_name, &storage)?; + )* + #( #subgroup_ty::serialize_subgroup::(world, map)?; )* + Ok(()) + } - struct ComponentVisitor<'a>(&'a mut _specs::World, &'a [_specs::Entity]); - impl<'a, 'de> _serde::de::Visitor<'de> for ComponentVisitor<'a> { - type Value = (); - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "a map of component identifiers to packed data") - } + fn deserialize_group<'de, D: _serde::Deserializer<'de>>(world: &mut _specs::World, entities: &[_specs::Entity], deserializer: D) -> Result<(), D::Error> { + use std::fmt; - fn visit_map(self, mut map: M) -> Result<(), M::Error> - where M: _serde::de::MapAccess<'de> - { - #[allow(unused_variables)] - while let Some(key) = map.next_key::<&'de str>()? { - match key { - #( - #comp_serialize_name => { - let mut storage = self.0.write_with_id::<#comp_serialize_ty>(#comp_serialize_id); - let packed = map.next_value::<_specs::PackedData<#comp_serialize_ty2>>()?; - let _ = storage.merge(self.1, packed); - }, - )* - uncaught_key @ _ => { + struct ComponentVisitor<'a>(&'a mut _specs::World, &'a [_specs::Entity]); + impl<'a, 'de> _serde::de::Visitor<'de> for ComponentVisitor<'a> { + type Value = (); + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "a map of component identifiers to packed data") + } + + fn visit_map(self, mut map: M) -> Result<(), M::Error> + where M: _serde::de::MapAccess<'de> + { + #[allow(unused_variables)] + while let Some(key) = map.next_key::<&'de str>()? { + match key { #( - if let Some(()) = <#subgroup_ty as _specs::SerializeGroup>::deserialize_subgroup(self.0, self.1, uncaught_key, &mut map)? { - continue; // subgroup deserialized the components - } + #comp_serialize_name => { + let mut storage = self.0.write_with_id::<#comp_serialize_ty>(#comp_serialize_id); + let packed = map.next_value::<_specs::PackedData<#comp_serialize_ty2>>()?; + let _ = storage.merge(self.1, packed); + }, )* - continue; // not in the registered component list, ignore - }, + uncaught_key @ _ => { + #( + if let Some(()) = <#subgroup_ty as _specs::SerializeGroup>::deserialize_subgroup(self.0, self.1, uncaught_key, &mut map)? { + continue; // subgroup deserialized the components + } + )* + continue; // not in the registered component list, ignore + }, + } } - } - Ok(()) + Ok(()) + } } - } - Ok(deserializer.deserialize_map(ComponentVisitor(world, entities))?) - } + Ok(deserializer.deserialize_map(ComponentVisitor(world, entities))?) + } - fn deserialize_subgroup<'de, M>(world: &mut _specs::World, entities: &[_specs::Entity], key: &'de str, mut map: &mut M) -> Result, M::Error> - where M: _serde::de::MapAccess<'de> - { - #[allow(unused_variables)] - match key { - #( - #comp_serialize_name => { - let mut storage = world.write_with_id::<#comp_serialize_ty>(#comp_serialize_id); - let packed = map.next_value::<_specs::PackedData<#comp_serialize_ty2>>()?; - let _ = storage.merge(entities, packed); - Ok(Some(())) - }, - )* - uncaught_key @ _ => { + fn deserialize_subgroup<'de, M>(world: &mut _specs::World, entities: &[_specs::Entity], key: &'de str, mut map: &mut M) -> Result, M::Error> + where M: _serde::de::MapAccess<'de> + { + #[allow(unused_variables)] + match key { #( - if let Some(()) = #subgroup_ty::deserialize_subgroup(world, entities, uncaught_key, map)? { - return Ok(Some(())); - } + #comp_serialize_name => { + let mut storage = world.write_with_id::<#comp_serialize_ty>(#comp_serialize_id); + let packed = map.next_value::<_specs::PackedData<#comp_serialize_ty2>>()?; + let _ = storage.merge(entities, packed); + Ok(Some(())) + }, )* - Ok(None) - }, + uncaught_key @ _ => { + #( + if let Some(()) = #subgroup_ty::deserialize_subgroup(world, entities, uncaught_key, map)? { + return Ok(Some(())); + } + )* + Ok(None) + }, + } } } }; + // Normal expand (no serialization) let expanded = quote! { #[automatically_derived] @@ -194,7 +191,7 @@ pub fn expand_group(input: &DeriveInput) -> Result { // Wrap the expanded code to prevent context conflicts. let wrap = quote! { - #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] + #[allow(non_upper_case_globals, unused_mut, unused_attributes, unused_qualifications)] #[macro_use] const #dummy_const: () = { extern crate specs as _specs; @@ -253,7 +250,7 @@ impl Parameter { params.id = id; } else { - println!("{} is not a valid id", id); + panic!("{} is not a valid id", id); } }, _ => panic!("Unknown group attribute: {:?}", meta_item), diff --git a/specs/src/group.rs b/src/group.rs similarity index 100% rename from specs/src/group.rs rename to src/group.rs diff --git a/specs/src/join.rs b/src/join.rs similarity index 100% rename from specs/src/join.rs rename to src/join.rs diff --git a/specs/src/lib.rs b/src/lib.rs similarity index 99% rename from specs/src/lib.rs rename to src/lib.rs index f1fba7029..f1858a854 100644 --- a/specs/src/lib.rs +++ b/src/lib.rs @@ -225,7 +225,6 @@ pub type Entities<'a> = Fetch<'a, EntitiesRes>; /// An index is basically the id of an `Entity`. pub type Index = u32; -#[macro_export] mod group; mod join; mod storage; diff --git a/specs/src/storage/check.rs b/src/storage/check.rs similarity index 100% rename from specs/src/storage/check.rs rename to src/storage/check.rs diff --git a/specs/src/storage/data.rs b/src/storage/data.rs similarity index 100% rename from specs/src/storage/data.rs rename to src/storage/data.rs diff --git a/specs/src/storage/mod.rs b/src/storage/mod.rs similarity index 100% rename from specs/src/storage/mod.rs rename to src/storage/mod.rs diff --git a/specs/src/storage/ser.rs b/src/storage/ser.rs similarity index 100% rename from specs/src/storage/ser.rs rename to src/storage/ser.rs diff --git a/specs/src/storage/storages.rs b/src/storage/storages.rs similarity index 100% rename from specs/src/storage/storages.rs rename to src/storage/storages.rs diff --git a/specs/src/storage/tests.rs b/src/storage/tests.rs similarity index 100% rename from specs/src/storage/tests.rs rename to src/storage/tests.rs diff --git a/specs/src/world.rs b/src/world.rs similarity index 99% rename from specs/src/world.rs rename to src/world.rs index 709cf27e3..83f64efde 100644 --- a/specs/src/world.rs +++ b/src/world.rs @@ -10,8 +10,6 @@ use serde::{Serialize, Serializer, Deserializer}; #[cfg(feature="serialize")] use group::SerializeGroup; -use group::ComponentGroup; - use hibitset::{AtomicBitSet, BitSet, BitSetOr}; use mopa::Any; use shred::{Fetch, FetchMut, Resource, Resources}; diff --git a/specs/tests/tests.rs b/tests/tests.rs similarity index 100% rename from specs/tests/tests.rs rename to tests/tests.rs