From b1063f77aaa0a80c42db58e926819578b1029725 Mon Sep 17 00:00:00 2001 From: recatek Date: Thu, 23 Nov 2023 01:54:05 -0500 Subject: [PATCH 01/11] Create 0000-cfg-attribute-in-tuple-type.md --- text/0000-cfg-attribute-in-tuple-type.md | 115 +++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 text/0000-cfg-attribute-in-tuple-type.md diff --git a/text/0000-cfg-attribute-in-tuple-type.md b/text/0000-cfg-attribute-in-tuple-type.md new file mode 100644 index 00000000000..b5fa8bae7be --- /dev/null +++ b/text/0000-cfg-attribute-in-tuple-type.md @@ -0,0 +1,115 @@ +- Feature Name: `cfg_attribute_in_tuple_type` +- Start Date: 2023-11-23 +- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) +- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) + +# Summary +[summary]: #summary + +Let's make it more elegant to conditionally compile tuple type declarations by allowing cfg-attributes directly on their element types. + +# Motivation +[motivation]: #motivation + +Currently, there is limited support for conditionally compiling tuple type declarations: + +```rust +type ConditionalTuple = (u32, i32, #[cfg(feature = "foo")] u8); +``` + +``` +error: expected type, found `#` + --> :1:36 + | +1 | type ConditionalTuple = (u32, i32, #[cfg(feature = "foo")] u8); + | ^ expected type +``` + +As in RFC #3399, some workarounds exist, but they can result in combinatorial boilerplate: + +```rust +// GOAL: +// type ConditionalTuple = ( +// u32, +// i32, +// #[cfg(feature = "foo")] u8, +// #[cfg(feature = "bar")] i8, +// ); + +// CURRENT: +#[cfg(all(feature = "foo", feature = "bar"))] +type ConditionalTuple = (u32, i32, u8, i8); +#[cfg(all(feature = "foo", not(feature = "bar")))] +type ConditionalTuple = (u32, i32, u8); +#[cfg(all(not(feature = "foo"), feature = "bar"))] +type ConditionalTuple = (u32, i32, i8); +#[cfg(all(not(feature = "foo"), not(feature = "bar")))] +type ConditionalTuple = (u32, i32); +``` + +One could also use a struct and attach cfg-attributes to its members, but this loses the compositional advantages of using a tuple. There are situations, especially when working with generics, where tuples are used purely for type communication rather than actual structure or storage. Structs can't easily serve this use case. + +Importantly, Rust already supports per-element cfg-attributes in tuple *initialization*. The following is legal Rust code and functions as expected: + +```rust +pub fn main() { + let x = (1u32, 4i32, #[cfg(all())] 23u8); + println!("{}", x.2) // Output: 23 +} +``` + +So it makes sense to support it in tuple type declaration as well. + +# Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +Tuple type declarations can use cfg-attributes on individual elements, like so: + +```rust +type MyTuple = ( + SomeTypeA, + #[cfg(something_a)] SomeTypeB, + #[cfg(something_b)] SomeTypeC, +) +``` + +and in other situations where tuple types are declared, such as in function arguments. These will conditionally include or exclude the type in that tuple (affecting the tuple's length) based on the compile-time evaluation result of each `#[cfg]` predicate. + +# Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + +This RFC proposes changing the syntax of the `TupleType` (see 10.1.5 in the Rust reference) to include `OuterAttribute*` before each occurrence of `Type`. These attributes can decorate each individual type (up to the comma or closing paren). In practice, at least within the scope of this RFC, only cfg-attributes need to be supported in this position. + +# Drawbacks +[drawbacks]: #drawbacks + +As with any feature, this adds complication to the language and grammar. Conditionally compiling tuple type elements can be a semver breaking change, but not any more than with the already existing workarounds. + +# Rationale and alternatives +[rationale-and-alternatives]: #rationale-and-alternatives + +(See RFC #3399 for a similar write-up.) + +The need for conditionally compiling tuple types can arise in applications with different deployment targets or that want to release +builds with different sets of functionality (e.g. client, server, editor, demo, etc.). It would be useful to support cfg-attributes +directly here without requiring workarounds to achieve this functionality. Macros, proc macros, and so on are also ways to conditionally +compile tuple types, but these also introduce at least one level of obfuscation from the core goal. Finally, tuples can be wholly +duplicated under different cfg-attributes, but this scales poorly with both the size and intricacy of the tuple and the number of +interacting attributes (which may grow combinatorically), and can introduce a maintenance burden from repeated code. + +It also makes sense in this instance to support cfg-attributes here because they are already supported in this manner for tuple initialization. + +# Prior art +[prior-art]: #prior-art + +I'm not aware of any prior work in adding this to the language. + +# Unresolved questions +[unresolved-questions]: #unresolved-questions + +I don't have any unresolved questions for this RFC. + +# Future possibilities +[future-possibilities]: #future-possibilities + +I believe this change is relatively self-contained, though I do believe it's worth continuing to look for additional places where support for cfg-attributes makes sense to add. Conditional compilation is very important, especially in some domains, and requiring workarounds and additional boilerplate to support it is not ideal. From c121333632c9459e422470e4e41c976e47db843d Mon Sep 17 00:00:00 2001 From: recatek Date: Thu, 23 Nov 2023 01:58:22 -0500 Subject: [PATCH 02/11] Update 0000-cfg-attribute-in-tuple-type.md --- text/0000-cfg-attribute-in-tuple-type.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/text/0000-cfg-attribute-in-tuple-type.md b/text/0000-cfg-attribute-in-tuple-type.md index b5fa8bae7be..76cf4b638d1 100644 --- a/text/0000-cfg-attribute-in-tuple-type.md +++ b/text/0000-cfg-attribute-in-tuple-type.md @@ -47,9 +47,9 @@ type ConditionalTuple = (u32, i32, i8); type ConditionalTuple = (u32, i32); ``` -One could also use a struct and attach cfg-attributes to its members, but this loses the compositional advantages of using a tuple. There are situations, especially when working with generics, where tuples are used purely for type communication rather than actual structure or storage. Structs can't easily serve this use case. +One could also use a struct and attach cfg-attributes to its members, but this loses the compositional and syntactical advantages of using a tuple. For example, there are situations (e.g. with generics) where tuples are used for type communication rather than actual structure or storage. Structs can't easily serve this use case. -Importantly, Rust already supports per-element cfg-attributes in tuple *initialization*. The following is legal Rust code and functions as expected: +Importantly, Rust already supports per-element cfg-attributes in tuple *initialization*. The following is legal Rust code and functions as expected, even though the resulting type of `x` can't be expressed very easily: ```rust pub fn main() { From 5978c74c79a02625d6f0cdbdb4f558ec4aa8a737 Mon Sep 17 00:00:00 2001 From: recatek Date: Thu, 23 Nov 2023 02:00:45 -0500 Subject: [PATCH 03/11] Adding links to RFC #3399 --- text/0000-cfg-attribute-in-tuple-type.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/text/0000-cfg-attribute-in-tuple-type.md b/text/0000-cfg-attribute-in-tuple-type.md index 76cf4b638d1..5ec840102be 100644 --- a/text/0000-cfg-attribute-in-tuple-type.md +++ b/text/0000-cfg-attribute-in-tuple-type.md @@ -25,7 +25,7 @@ error: expected type, found `#` | ^ expected type ``` -As in RFC #3399, some workarounds exist, but they can result in combinatorial boilerplate: +As with [RFC #3399](https://rust-lang.github.io/rfcs/3399-cfg-attribute-in-where.html), some workarounds exist, but they can result in combinatorial boilerplate: ```rust // GOAL: @@ -88,7 +88,7 @@ As with any feature, this adds complication to the language and grammar. Conditi # Rationale and alternatives [rationale-and-alternatives]: #rationale-and-alternatives -(See RFC #3399 for a similar write-up.) +(See [RFC #3399](https://rust-lang.github.io/rfcs/3399-cfg-attribute-in-where.html) for a similar write-up.) The need for conditionally compiling tuple types can arise in applications with different deployment targets or that want to release builds with different sets of functionality (e.g. client, server, editor, demo, etc.). It would be useful to support cfg-attributes From 5ed87ae0a9358f0fdab6e8b5524566b64f4786e6 Mon Sep 17 00:00:00 2001 From: recatek Date: Thu, 23 Nov 2023 02:01:31 -0500 Subject: [PATCH 04/11] Update 0000-cfg-attribute-in-tuple-type.md --- text/0000-cfg-attribute-in-tuple-type.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-cfg-attribute-in-tuple-type.md b/text/0000-cfg-attribute-in-tuple-type.md index 5ec840102be..5647872befd 100644 --- a/text/0000-cfg-attribute-in-tuple-type.md +++ b/text/0000-cfg-attribute-in-tuple-type.md @@ -112,4 +112,4 @@ I don't have any unresolved questions for this RFC. # Future possibilities [future-possibilities]: #future-possibilities -I believe this change is relatively self-contained, though I do believe it's worth continuing to look for additional places where support for cfg-attributes makes sense to add. Conditional compilation is very important, especially in some domains, and requiring workarounds and additional boilerplate to support it is not ideal. +I believe this change is relatively self-contained, though I also think it's worth continuing to look for additional places where support for cfg-attributes makes sense to add. Conditional compilation is very important, especially in some domains, and requiring workarounds and additional boilerplate to support it is not ideal. From f5e1022da8cba9eb6f5ffe3bb0c158bddcd64fee Mon Sep 17 00:00:00 2001 From: recatek Date: Thu, 23 Nov 2023 02:06:33 -0500 Subject: [PATCH 05/11] Assigning RFC number --- ...ute-in-tuple-type.md => 3532-cfg-attribute-in-tuple-type.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename text/{0000-cfg-attribute-in-tuple-type.md => 3532-cfg-attribute-in-tuple-type.md} (98%) diff --git a/text/0000-cfg-attribute-in-tuple-type.md b/text/3532-cfg-attribute-in-tuple-type.md similarity index 98% rename from text/0000-cfg-attribute-in-tuple-type.md rename to text/3532-cfg-attribute-in-tuple-type.md index 5647872befd..bc8f11be5ab 100644 --- a/text/0000-cfg-attribute-in-tuple-type.md +++ b/text/3532-cfg-attribute-in-tuple-type.md @@ -1,6 +1,6 @@ - Feature Name: `cfg_attribute_in_tuple_type` - Start Date: 2023-11-23 -- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) +- RFC PR: [rust-lang/rfcs#3532](https://github.com/rust-lang/rfcs/pull/3532) - Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) # Summary From 36f25576394c742d7bba34164be26ae211764f53 Mon Sep 17 00:00:00 2001 From: recatek Date: Sun, 26 Nov 2023 13:59:07 -0500 Subject: [PATCH 06/11] Adding more information about use cases in the motivation section --- text/3532-cfg-attribute-in-tuple-type.md | 246 ++++++++++++++++++++++- 1 file changed, 235 insertions(+), 11 deletions(-) diff --git a/text/3532-cfg-attribute-in-tuple-type.md b/text/3532-cfg-attribute-in-tuple-type.md index bc8f11be5ab..5da1df7cbc8 100644 --- a/text/3532-cfg-attribute-in-tuple-type.md +++ b/text/3532-cfg-attribute-in-tuple-type.md @@ -11,6 +11,8 @@ Let's make it more elegant to conditionally compile tuple type declarations by a # Motivation [motivation]: #motivation +### Consistency + Currently, there is limited support for conditionally compiling tuple type declarations: ```rust @@ -47,9 +49,7 @@ type ConditionalTuple = (u32, i32, i8); type ConditionalTuple = (u32, i32); ``` -One could also use a struct and attach cfg-attributes to its members, but this loses the compositional and syntactical advantages of using a tuple. For example, there are situations (e.g. with generics) where tuples are used for type communication rather than actual structure or storage. Structs can't easily serve this use case. - -Importantly, Rust already supports per-element cfg-attributes in tuple *initialization*. The following is legal Rust code and functions as expected, even though the resulting type of `x` can't be expressed very easily: +Rust already supports per-element cfg-attributes in tuple *initialization*. The following is legal Rust code and functions as expected, even though the resulting type of `x` can't be expressed very easily: ```rust pub fn main() { @@ -58,7 +58,236 @@ pub fn main() { } ``` -So it makes sense to support it in tuple type declaration as well. +Similarly, cfg-attributes are permitted on types in tuple structs, like so: + +``` +pub struct SomeStruct(u32, #[cfg(feature = "foo")] bool); +``` + +So it makes sense to support it in regular tuple type declaration as well. + +### Use Cases + +While structs support cfg-attributes on their members, tuples serve an important purpose in a number of applications that can't easily be replicated with structs. One common example is for achieving variadic-like behavior for constructing and accessing struct-of-array (SoA) data structures. These data structures break large data blocks into modular data components in individual contiguous memory blocks for reusable composition and optimizations via SIMD and improved cache behavior. This is especially prevalent in Entity Component System libraries like [bevy](https://docs.rs/bevy_ecs) and [hecs](https://docs.rs/hecs). For example, to perform a world query in hecs, the user constructs an iterator using a type-tuple like so: + +```rust +for (id, (number, &flag)) in world.query_mut::<(&mut i32, &bool)>() { + if flag { *number *= 2; } +} +``` + +Tuples have a number of unique advantages in this paradigm. For one, they avoid boilerplate due to their ability to be anonymously constructed on the fly. Additionally, tuples can be concatenated and joined (e.g. via the [tuple](https://docs.rs/tuple) crate). This allows more advanced ECS libraries and other similar tools to provide support for pre-determined bundles of components, or use tuple nesting to group logic and functionality. One could theoretically define functions like `query_mut1`, `query_mut2`, and so on, but the ergonomics of the tuple approach win out in practice. + +In this situation, cfg-attributes come into play when building ECS archetypes (a pre-determined collection of components for a type of entity) for different platforms or deployment targets. Say for example that we were creating a multiplayer asteroids game in an Entity Component System. If we wanted to statically define our archetypes at compile-time (as is the case in [gecs](https://docs.rs/gecs)), it might look something like this: + +```rust +type ShipArchetype = EcsArchetype<( + TransformComponent, + VelocityComponent, + PhysicsComponent, + ColliderComponent, + EngineComponent, + HealthComponent, + WeaponComponent, + EnergyComponent, + SpriteComponent, + AudioComponent, +)>; +``` + +Since this is a multiplayer game, we may want some components to exist solely on the server or on the client, both for security reasons and also for optimization or performance reasons. The sprite and audio components for example serve no purpose on the server as the server does not render graphics or play audio. In games in other languages, it is common practice to use conditional compilation to avoid putting code in various build targets that serve no purpose, waste resources, or potentially leak information to cheaters. So in this case we will restrict these two components to the `client` feature, like so: + +```rust +type ShipArchetype = EcsArchetype<( + TransformComponent, + VelocityComponent, + PhysicsComponent, + ColliderComponent, + EngineComponent, + HealthComponent, + WeaponComponent, + EnergyComponent, + #[cfg(feature = "client")] SpriteComponent, + #[cfg(feature = "client")] AudioComponent, +)>; +``` + +Additionally, we need some components to handle serializing the network state, performing dead reckoning, and sending that information to the client from the server. So we will add a `StateStorageComponent` and a `DeltaCompressionComponent`, and restrict those to the server, since the client does not perform these calculations and we want to avoid giving clients this information to help defeat, or at least delay the arms race against, cheaters. + +```rust +type ShipArchetype = EcsArchetype<( + TransformComponent, + VelocityComponent, + PhysicsComponent, + ColliderComponent, + EngineComponent, + HealthComponent, + WeaponComponent, + EnergyComponent, + #[cfg(feature = "client")] SpriteComponent, + #[cfg(feature = "client")] AudioComponent, + #[cfg(feature = "server")] StateStorageComponent, + #[cfg(feature = "server")] DeltaCompressionComponent, +)>; +``` + +Finally, we want some debug information for diagnosing physics and damage calculation issues. We build a component to store this intermediate data, but we don't want to ship it in the final game because it's just for aid in development. We'll create a `DebugDrawComponent` and add it to our ship archetype as well, but only when the game is built in editor mode because it's quite expensive to do these extra calculations and draw debug information every frame. + +```rust +type ShipArchetype = EcsArchetype<( + TransformComponent, + VelocityComponent, + PhysicsComponent, + ColliderComponent, + EngineComponent, + HealthComponent, + WeaponComponent, + EnergyComponent, + #[cfg(feature = "client")] SpriteComponent, + #[cfg(feature = "client")] AudioComponent, + #[cfg(feature = "server")] StateStorageComponent, + #[cfg(feature = "server")] DeltaCompressionComponent, + #[cfg(feature = "editor")] DebugDrawComponent, +)>; +``` + +This represents our archetype with the various common and situational components based on its build and deployment target. With this decoration each component is decorated with the context in which it appears, and requires no inference or indirection via macros to generate or read. By comparison, here is how this would be written in Rust today, keeping in mind that a build could be any combination of client, server, and editor for development and debugging purposes (akin to Unreal Engine's "play in editor" feature): + +```rust +#[cfg(feature = "client")] +#[cfg(feature = "server")] +#[cfg(feature = "editor")] +type ShipArchetype = EcsArchetype<( + TransformComponent, + VelocityComponent, + PhysicsComponent, + ColliderComponent, + EngineComponent, + HealthComponent, + WeaponComponent, + EnergyComponent, + SpriteComponent, + AudioComponent, + StateStorageComponent, + DeltaCompressionComponent, + DebugDrawComponent, +)>; + +#[cfg(not(feature = "client"))] +#[cfg(feature = "server")] +#[cfg(feature = "editor")] +type ShipArchetype = EcsArchetype<( + TransformComponent, + VelocityComponent, + PhysicsComponent, + ColliderComponent, + EngineComponent, + HealthComponent, + WeaponComponent, + EnergyComponent, + StateStorageComponent, + DeltaCompressionComponent, + DebugDrawComponent, +)>; + +#[cfg(feature = "client")] +#[cfg(not(feature = "server"))] +#[cfg(feature = "editor")] +type ShipArchetype = EcsArchetype<( + TransformComponent, + VelocityComponent, + PhysicsComponent, + ColliderComponent, + EngineComponent, + HealthComponent, + WeaponComponent, + EnergyComponent, + SpriteComponent, + AudioComponent, + DebugDrawComponent, +)>; + +#[cfg(not(feature = "client"))] +#[cfg(not(feature = "server"))] +#[cfg(feature = "editor")] +type ShipArchetype = EcsArchetype<( + TransformComponent, + VelocityComponent, + PhysicsComponent, + ColliderComponent, + EngineComponent, + HealthComponent, + WeaponComponent, + EnergyComponent, + DebugDrawComponent, +)>; + +#[cfg(feature = "client")] +#[cfg(feature = "server")] +#[cfg(not(feature = "editor"))] +type ShipArchetype = EcsArchetype<( + TransformComponent, + VelocityComponent, + PhysicsComponent, + ColliderComponent, + EngineComponent, + HealthComponent, + WeaponComponent, + EnergyComponent, + SpriteComponent, + AudioComponent, + StateStorageComponent, + DeltaCompressionComponent, +)>; + +#[cfg(not(feature = "client"))] +#[cfg(feature = "server")] +#[cfg(not(feature = "editor"))] +type ShipArchetype = EcsArchetype<( + TransformComponent, + VelocityComponent, + PhysicsComponent, + ColliderComponent, + EngineComponent, + HealthComponent, + WeaponComponent, + EnergyComponent, + StateStorageComponent, + DeltaCompressionComponent, +)>; + +#[cfg(feature = "client")] +#[cfg(not(feature = "server"))] +#[cfg(not(feature = "editor"))] +type ShipArchetype = EcsArchetype<( + TransformComponent, + VelocityComponent, + PhysicsComponent, + ColliderComponent, + EngineComponent, + HealthComponent, + WeaponComponent, + EnergyComponent, + SpriteComponent, + AudioComponent, +)>; + +#[cfg(not(feature = "client"))] +#[cfg(not(feature = "server"))] +#[cfg(not(feature = "editor"))] +type ShipArchetype = EcsArchetype<( + TransformComponent, + VelocityComponent, + PhysicsComponent, + ColliderComponent, + EngineComponent, + HealthComponent, + WeaponComponent, + EnergyComponent, +)>; +``` + +This would likely need to be generated via macro in practice, and the macro itself would have to parse the cfg-attributes to produce these combinatorial outputs. However, macros aren't supported in all positions where tuples are supported (e.g. as type arguments), and so even with macros this would create levels of indirection and require alias definitions. The hecs query example above could not have an element conditionally gated via a macro without first declaring an alias for that query's tuple type outside of the position where the query iteration occurs. # Guide-level explanation [guide-level-explanation]: #guide-level-explanation @@ -90,14 +319,9 @@ As with any feature, this adds complication to the language and grammar. Conditi (See [RFC #3399](https://rust-lang.github.io/rfcs/3399-cfg-attribute-in-where.html) for a similar write-up.) -The need for conditionally compiling tuple types can arise in applications with different deployment targets or that want to release -builds with different sets of functionality (e.g. client, server, editor, demo, etc.). It would be useful to support cfg-attributes -directly here without requiring workarounds to achieve this functionality. Macros, proc macros, and so on are also ways to conditionally -compile tuple types, but these also introduce at least one level of obfuscation from the core goal. Finally, tuples can be wholly -duplicated under different cfg-attributes, but this scales poorly with both the size and intricacy of the tuple and the number of -interacting attributes (which may grow combinatorically), and can introduce a maintenance burden from repeated code. +The need for conditionally compiling tuple types can arise in applications with different deployment targets or that want to release builds with different sets of functionality (e.g. client, server, editor, demo, etc.). It would be useful to support cfg-attributes directly here without requiring workarounds to achieve this functionality. Macros, proc macros, and so on are also ways to conditionally compile tuple types, but these also introduce at least one level of obfuscation from the core goal and can't be used everywhere a tuple can be. Finally, tuples can be wholly duplicated under different cfg-attributes, but this scales poorly with both the size and intricacy of the tuple and the number of interacting attributes (which may grow combinatorically), and can introduce a maintenance burden from repeated code. -It also makes sense in this instance to support cfg-attributes here because they are already supported in this manner for tuple initialization. +It also makes sense in this instance to support cfg-attributes here because they are already supported in this manner for tuple initialization and for tuple struct declaration. # Prior art [prior-art]: #prior-art From 0ae4378bad69e7b7d5b8de5f5dc1149b53c8384a Mon Sep 17 00:00:00 2001 From: recatek Date: Sun, 26 Nov 2023 14:08:20 -0500 Subject: [PATCH 07/11] Clarifying interaction with macros and combinatorial expansion --- text/3532-cfg-attribute-in-tuple-type.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/3532-cfg-attribute-in-tuple-type.md b/text/3532-cfg-attribute-in-tuple-type.md index 5da1df7cbc8..c998d9f1fcd 100644 --- a/text/3532-cfg-attribute-in-tuple-type.md +++ b/text/3532-cfg-attribute-in-tuple-type.md @@ -287,7 +287,7 @@ type ShipArchetype = EcsArchetype<( )>; ``` -This would likely need to be generated via macro in practice, and the macro itself would have to parse the cfg-attributes to produce these combinatorial outputs. However, macros aren't supported in all positions where tuples are supported (e.g. as type arguments), and so even with macros this would create levels of indirection and require alias definitions. The hecs query example above could not have an element conditionally gated via a macro without first declaring an alias for that query's tuple type outside of the position where the query iteration occurs. +This would likely need to be generated via macro in practice, and the macro itself would have to parse the cfg-attributes to produce these combinatorial outputs. However, macros aren't an easy fix in all positions where tuples are supported (e.g. as type arguments), and so even with macros this would create levels of indirection and require alias definitions. The hecs query example above could not easily have an element conditionally gated via a macro without first declaring an alias for that query's tuple type outside of the position where the query iteration occurs. This is because doing so would likely require the macro to be able to generate code outside of its immediate context to function (i.e. to branch based on each cfg-attribute involved). # Guide-level explanation [guide-level-explanation]: #guide-level-explanation From a2f76ab762274bc69401e8a8aa3cf7cdcff7eb4f Mon Sep 17 00:00:00 2001 From: recatek Date: Sun, 26 Nov 2023 14:20:40 -0500 Subject: [PATCH 08/11] Fixing up example cfg-attributes --- text/3532-cfg-attribute-in-tuple-type.md | 32 ++++++------------------ 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/text/3532-cfg-attribute-in-tuple-type.md b/text/3532-cfg-attribute-in-tuple-type.md index c998d9f1fcd..cffd6803d58 100644 --- a/text/3532-cfg-attribute-in-tuple-type.md +++ b/text/3532-cfg-attribute-in-tuple-type.md @@ -154,9 +154,7 @@ type ShipArchetype = EcsArchetype<( This represents our archetype with the various common and situational components based on its build and deployment target. With this decoration each component is decorated with the context in which it appears, and requires no inference or indirection via macros to generate or read. By comparison, here is how this would be written in Rust today, keeping in mind that a build could be any combination of client, server, and editor for development and debugging purposes (akin to Unreal Engine's "play in editor" feature): ```rust -#[cfg(feature = "client")] -#[cfg(feature = "server")] -#[cfg(feature = "editor")] +#[cfg(all(feature = "client", feature = "server", feature = "editor"))] type ShipArchetype = EcsArchetype<( TransformComponent, VelocityComponent, @@ -173,9 +171,7 @@ type ShipArchetype = EcsArchetype<( DebugDrawComponent, )>; -#[cfg(not(feature = "client"))] -#[cfg(feature = "server")] -#[cfg(feature = "editor")] +#[cfg(all(not(feature = "client"), feature = "server", feature = "editor"))] type ShipArchetype = EcsArchetype<( TransformComponent, VelocityComponent, @@ -190,9 +186,7 @@ type ShipArchetype = EcsArchetype<( DebugDrawComponent, )>; -#[cfg(feature = "client")] -#[cfg(not(feature = "server"))] -#[cfg(feature = "editor")] +#[cfg(all(feature = "client", not(feature = "server"), feature = "editor"))] type ShipArchetype = EcsArchetype<( TransformComponent, VelocityComponent, @@ -207,9 +201,7 @@ type ShipArchetype = EcsArchetype<( DebugDrawComponent, )>; -#[cfg(not(feature = "client"))] -#[cfg(not(feature = "server"))] -#[cfg(feature = "editor")] +#[cfg(all(not(feature = "client"), not(feature = "server"), feature = "editor")))] type ShipArchetype = EcsArchetype<( TransformComponent, VelocityComponent, @@ -222,9 +214,7 @@ type ShipArchetype = EcsArchetype<( DebugDrawComponent, )>; -#[cfg(feature = "client")] -#[cfg(feature = "server")] -#[cfg(not(feature = "editor"))] +#[cfg(all(feature = "client", feature = "server", not(feature = "editor")))] type ShipArchetype = EcsArchetype<( TransformComponent, VelocityComponent, @@ -240,9 +230,7 @@ type ShipArchetype = EcsArchetype<( DeltaCompressionComponent, )>; -#[cfg(not(feature = "client"))] -#[cfg(feature = "server")] -#[cfg(not(feature = "editor"))] +#[cfg(all(not(feature = "client"), feature = "server", not(feature = "editor")))] type ShipArchetype = EcsArchetype<( TransformComponent, VelocityComponent, @@ -256,9 +244,7 @@ type ShipArchetype = EcsArchetype<( DeltaCompressionComponent, )>; -#[cfg(feature = "client")] -#[cfg(not(feature = "server"))] -#[cfg(not(feature = "editor"))] +#[cfg(all(feature = "client", not(feature = "server"), not(feature = "editor")))] type ShipArchetype = EcsArchetype<( TransformComponent, VelocityComponent, @@ -272,9 +258,7 @@ type ShipArchetype = EcsArchetype<( AudioComponent, )>; -#[cfg(not(feature = "client"))] -#[cfg(not(feature = "server"))] -#[cfg(not(feature = "editor"))] +#[cfg(all(not(feature = "client"), not(feature = "server"), not(feature = "editor")))] type ShipArchetype = EcsArchetype<( TransformComponent, VelocityComponent, From 7d417e2bc2feb6a2e8adf4594cb296abc9a7ee5d Mon Sep 17 00:00:00 2001 From: recatek Date: Sun, 26 Nov 2023 14:58:22 -0500 Subject: [PATCH 09/11] Minor fixes for code formatting --- text/3532-cfg-attribute-in-tuple-type.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/text/3532-cfg-attribute-in-tuple-type.md b/text/3532-cfg-attribute-in-tuple-type.md index cffd6803d58..adcbf2794eb 100644 --- a/text/3532-cfg-attribute-in-tuple-type.md +++ b/text/3532-cfg-attribute-in-tuple-type.md @@ -60,7 +60,7 @@ pub fn main() { Similarly, cfg-attributes are permitted on types in tuple structs, like so: -``` +```rust pub struct SomeStruct(u32, #[cfg(feature = "foo")] bool); ``` @@ -201,7 +201,7 @@ type ShipArchetype = EcsArchetype<( DebugDrawComponent, )>; -#[cfg(all(not(feature = "client"), not(feature = "server"), feature = "editor")))] +#[cfg(all(not(feature = "client"), not(feature = "server"), feature = "editor"))] type ShipArchetype = EcsArchetype<( TransformComponent, VelocityComponent, From 24e74b44c7713284cf0296ba7a8f4a13c65f7306 Mon Sep 17 00:00:00 2001 From: recatek Date: Sun, 3 Dec 2023 12:08:18 -0500 Subject: [PATCH 10/11] Update text/3532-cfg-attribute-in-tuple-type.md Co-authored-by: oliver <151407407+kwfn@users.noreply.github.com> --- text/3532-cfg-attribute-in-tuple-type.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/3532-cfg-attribute-in-tuple-type.md b/text/3532-cfg-attribute-in-tuple-type.md index adcbf2794eb..dea8a9b2733 100644 --- a/text/3532-cfg-attribute-in-tuple-type.md +++ b/text/3532-cfg-attribute-in-tuple-type.md @@ -112,7 +112,7 @@ type ShipArchetype = EcsArchetype<( )>; ``` -Additionally, we need some components to handle serializing the network state, performing dead reckoning, and sending that information to the client from the server. So we will add a `StateStorageComponent` and a `DeltaCompressionComponent`, and restrict those to the server, since the client does not perform these calculations and we want to avoid giving clients this information to help defeat, or at least delay the arms race against, cheaters. +Additionally, we need some components to handle serializing the network state, performing dead reckoning, and sending that information to the client from the server. So we will add a `StateStorageComponent` and a `DeltaCompressionComponent`, and restrict those to the server, since the client does not perform these calculations and we want to avoid giving clients this information to help confound, or at least delay, cheaters. ```rust type ShipArchetype = EcsArchetype<( From f69a625dcff3db63c26a2d88bbb4c35e8a2cd813 Mon Sep 17 00:00:00 2001 From: recatek Date: Sun, 3 Dec 2023 12:13:28 -0500 Subject: [PATCH 11/11] Update 3532-cfg-attribute-in-tuple-type.md --- text/3532-cfg-attribute-in-tuple-type.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/3532-cfg-attribute-in-tuple-type.md b/text/3532-cfg-attribute-in-tuple-type.md index dea8a9b2733..62cf5509ac7 100644 --- a/text/3532-cfg-attribute-in-tuple-type.md +++ b/text/3532-cfg-attribute-in-tuple-type.md @@ -112,7 +112,7 @@ type ShipArchetype = EcsArchetype<( )>; ``` -Additionally, we need some components to handle serializing the network state, performing dead reckoning, and sending that information to the client from the server. So we will add a `StateStorageComponent` and a `DeltaCompressionComponent`, and restrict those to the server, since the client does not perform these calculations and we want to avoid giving clients this information to help confound, or at least delay, cheaters. +Additionally, we need some components to handle serializing the network state, performing dead reckoning, and sending that information to the client from the server. So we will add a `StateStorageComponent` and a `DeltaCompressionComponent`, and restrict those to the server, since the client does not perform these calculations and we want to avoid giving clients this information in order to help confound cheaters. ```rust type ShipArchetype = EcsArchetype<(