From db5c31e1c4d3c42c744470aa602432dc0b0cafb0 Mon Sep 17 00:00:00 2001 From: Zachary Harrold Date: Tue, 31 Dec 2024 08:01:13 +1100 Subject: [PATCH] Add `no_std` support to `bevy_transform` (#17030) # Objective - Contributes to #15460 ## Solution - Added the following features: - `std` (default) - `alloc` (default) - `bevy_reflect` (default) - `libm` ## Testing - CI ## Notes - `alloc` feature added to allow using this crate in `no_alloc` environments. - `bevy_reflect` was previously always enabled when `bevy-support` was enabled, which isn't how most other crates handle reflection. I've brought this in line with how most crates gate `bevy_reflect`. --- crates/bevy_transform/Cargo.toml | 67 +++++++++++++------ .../src/components/global_transform.rs | 26 ++++--- .../src/components/transform.rs | 17 ++--- crates/bevy_transform/src/lib.rs | 4 ++ crates/bevy_transform/src/plugins.rs | 11 ++- crates/bevy_transform/src/systems.rs | 1 + tools/ci/src/commands/compile_check_no_std.rs | 8 +++ 7 files changed, 93 insertions(+), 41 deletions(-) diff --git a/crates/bevy_transform/Cargo.toml b/crates/bevy_transform/Cargo.toml index fdc02f2386..672383dc44 100644 --- a/crates/bevy_transform/Cargo.toml +++ b/crates/bevy_transform/Cargo.toml @@ -10,16 +10,16 @@ keywords = ["bevy"] [dependencies] # bevy -bevy_app = { path = "../bevy_app", version = "0.15.0-dev", optional = true } -bevy_ecs = { path = "../bevy_ecs", version = "0.15.0-dev", features = [ - "bevy_reflect", +bevy_app = { path = "../bevy_app", version = "0.15.0-dev", default-features = false, optional = true } +bevy_ecs = { path = "../bevy_ecs", version = "0.15.0-dev", default-features = false, optional = true } +bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.15.0-dev", default-features = false, features = [ + "bevy_app", ], optional = true } -bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.15.0-dev", optional = true } bevy_math = { path = "../bevy_math", version = "0.15.0-dev", default-features = false } -bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev", features = [ - "bevy", +bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev", default-features = false, optional = true } +serde = { version = "1", default-features = false, features = [ + "derive", ], optional = true } -serde = { version = "1", features = ["derive"], optional = true } thiserror = { version = "2", default-features = false } derive_more = { version = "1", default-features = false, features = ["from"] } @@ -31,24 +31,51 @@ bevy_math = { path = "../bevy_math", version = "0.15.0-dev", default-features = approx = "0.5.1" [features] -# Adds normal Bevy impls like deriving components, bundles, reflection, as well as adding -# systems for transform propagation and more. -# This exists because it allows opting out of all of this, leaving only a bare-bones transform struct, -# which enables users to depend on that without needing the larger Bevy dependency tree. -bevy-support = [ - "dep:bevy_app", - "dep:bevy_ecs", - "dep:bevy_hierarchy", - "dep:bevy_reflect", - "bevy_math/bevy_reflect", -] - # Turning off default features leaves you with a barebones # definition of transform. -default = ["bevy-support"] +default = ["std", "bevy-support", "bevy_reflect"] +# Functionality + +## Adds normal Bevy impls like deriving components, bundles, reflection, as well as adding +## systems for transform propagation and more. +## This exists because it allows opting out of all of this, leaving only a bare-bones transform struct, +## which enables users to depend on that without needing the larger Bevy dependency tree. +bevy-support = ["alloc", "dep:bevy_app", "dep:bevy_ecs", "dep:bevy_hierarchy"] + +## Adds serialization support through `serde`. serialize = ["dep:serde", "bevy_math/serialize"] +## Adds runtime reflection support using `bevy_reflect`. +bevy_reflect = [ + "bevy-support", + "dep:bevy_reflect", + "bevy_math/bevy_reflect", + "bevy_ecs/bevy_reflect", + "bevy_app/bevy_reflect", +] + +# Platform Compatibility + +## Allows access to the `std` crate. Enabling this feature will prevent compilation +## on `no_std` targets, but provides access to certain additional features on +## supported platforms. +std = [ + "alloc", + "bevy_app?/std", + "bevy_ecs?/std", + "bevy_hierarchy?/std", + "bevy_math/std", + "bevy_reflect?/std", + "serde?/std", +] + +## Allows access to the `alloc` crate. +alloc = ["serde?/alloc"] + +## Uses the `libm` maths library instead of the one provided in `std` and `core`. +libm = ["bevy_math/libm"] + [lints] workspace = true diff --git a/crates/bevy_transform/src/components/global_transform.rs b/crates/bevy_transform/src/components/global_transform.rs index 9a9961c604..0a04baadaf 100644 --- a/crates/bevy_transform/src/components/global_transform.rs +++ b/crates/bevy_transform/src/components/global_transform.rs @@ -1,13 +1,18 @@ use core::ops::Mul; use super::Transform; -use bevy_math::{Affine3A, Dir3, Isometry3d, Mat4, Quat, Vec3, Vec3A}; -#[cfg(all(feature = "bevy-support", feature = "serialize"))] -use bevy_reflect::{ReflectDeserialize, ReflectSerialize}; +use bevy_math::{ops, Affine3A, Dir3, Isometry3d, Mat4, Quat, Vec3, Vec3A}; use derive_more::derive::From; + +#[cfg(all(feature = "bevy_reflect", feature = "serialize"))] +use bevy_reflect::{ReflectDeserialize, ReflectSerialize}; + #[cfg(feature = "bevy-support")] +use bevy_ecs::component::Component; + +#[cfg(feature = "bevy_reflect")] use { - bevy_ecs::{component::Component, reflect::ReflectComponent}, + bevy_ecs::reflect::ReflectComponent, bevy_reflect::{std_traits::ReflectDefault, Reflect}, }; @@ -42,26 +47,27 @@ use { /// [transform_example]: https://github.com/bevyengine/bevy/blob/latest/examples/transforms/transform.rs #[derive(Debug, PartialEq, Clone, Copy, From)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "bevy-support", derive(Component))] #[cfg_attr( - feature = "bevy-support", - derive(Component, Reflect), + feature = "bevy_reflect", + derive(Reflect), reflect(Component, Default, PartialEq, Debug) )] #[cfg_attr( - all(feature = "bevy-support", feature = "serialize"), + all(feature = "bevy_reflect", feature = "serialize"), reflect(Serialize, Deserialize) )] pub struct GlobalTransform(Affine3A); macro_rules! impl_local_axis { ($pos_name: ident, $neg_name: ident, $axis: ident) => { - #[doc=std::concat!("Return the local ", std::stringify!($pos_name), " vector (", std::stringify!($axis) ,").")] + #[doc=core::concat!("Return the local ", core::stringify!($pos_name), " vector (", core::stringify!($axis) ,").")] #[inline] pub fn $pos_name(&self) -> Dir3 { Dir3::new_unchecked((self.0.matrix3 * Vec3::$axis).normalize()) } - #[doc=std::concat!("Return the local ", std::stringify!($neg_name), " vector (-", std::stringify!($axis) ,").")] + #[doc=core::concat!("Return the local ", core::stringify!($neg_name), " vector (-", core::stringify!($axis) ,").")] #[inline] pub fn $neg_name(&self) -> Dir3 { -self.$pos_name() @@ -235,7 +241,7 @@ impl GlobalTransform { //Formula based on glam's implementation https://github.com/bitshifter/glam-rs/blob/2e4443e70c709710dfb25958d866d29b11ed3e2b/src/f32/affine3a.rs#L290 let det = self.0.matrix3.determinant(); Vec3::new( - self.0.matrix3.x_axis.length() * det.signum(), + self.0.matrix3.x_axis.length() * ops::copysign(1., det), self.0.matrix3.y_axis.length(), self.0.matrix3.z_axis.length(), ) diff --git a/crates/bevy_transform/src/components/transform.rs b/crates/bevy_transform/src/components/transform.rs index 1fcc87c272..c07a8c52e5 100644 --- a/crates/bevy_transform/src/components/transform.rs +++ b/crates/bevy_transform/src/components/transform.rs @@ -1,11 +1,12 @@ use super::GlobalTransform; use bevy_math::{Affine3A, Dir3, Isometry3d, Mat3, Mat4, Quat, Vec3}; use core::ops::Mul; + #[cfg(feature = "bevy-support")] -use { - bevy_ecs::{component::Component, prelude::require, reflect::ReflectComponent}, - bevy_reflect::prelude::*, -}; +use bevy_ecs::{component::Component, prelude::require}; + +#[cfg(feature = "bevy_reflect")] +use {bevy_ecs::reflect::ReflectComponent, bevy_reflect::prelude::*}; /// Describe the position of an entity. If the entity has a parent, the position is relative /// to its parent position. @@ -38,14 +39,14 @@ use { /// [transform_example]: https://github.com/bevyengine/bevy/blob/latest/examples/transforms/transform.rs #[derive(Debug, PartialEq, Clone, Copy)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "bevy-support", derive(Component), require(GlobalTransform))] #[cfg_attr( - feature = "bevy-support", - derive(Component, Reflect), - require(GlobalTransform), + feature = "bevy_reflect", + derive(Reflect), reflect(Component, Default, PartialEq, Debug) )] #[cfg_attr( - all(feature = "bevy-support", feature = "serialize"), + all(feature = "bevy_reflect", feature = "serialize"), reflect(Serialize, Deserialize) )] pub struct Transform { diff --git a/crates/bevy_transform/src/lib.rs b/crates/bevy_transform/src/lib.rs index 8aed69e08b..d9b67f7cfc 100644 --- a/crates/bevy_transform/src/lib.rs +++ b/crates/bevy_transform/src/lib.rs @@ -4,6 +4,10 @@ html_logo_url = "https://bevyengine.org/assets/icon.png", html_favicon_url = "https://bevyengine.org/assets/icon.png" )] +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(feature = "alloc")] +extern crate alloc; #[cfg(feature = "bevy-support")] pub mod commands; diff --git a/crates/bevy_transform/src/plugins.rs b/crates/bevy_transform/src/plugins.rs index 07bb35c311..e1339962ef 100644 --- a/crates/bevy_transform/src/plugins.rs +++ b/crates/bevy_transform/src/plugins.rs @@ -3,10 +3,13 @@ use bevy_ecs::schedule::{IntoSystemConfigs, IntoSystemSetConfigs, SystemSet}; use bevy_hierarchy::ValidParentCheckPlugin; use crate::{ - prelude::{GlobalTransform, Transform}, + components::GlobalTransform, systems::{propagate_transforms, sync_simple_transforms}, }; +#[cfg(feature = "bevy_reflect")] +use crate::components::Transform; + /// Set enum for the systems relating to transform propagation #[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)] pub enum TransformSystem { @@ -25,9 +28,11 @@ impl Plugin for TransformPlugin { #[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)] struct PropagateTransformsSet; + #[cfg(feature = "bevy_reflect")] app.register_type::() - .register_type::() - .add_plugins(ValidParentCheckPlugin::::default()) + .register_type::(); + + app.add_plugins(ValidParentCheckPlugin::::default()) .configure_sets( PostStartup, PropagateTransformsSet.in_set(TransformSystem::TransformPropagate), diff --git a/crates/bevy_transform/src/systems.rs b/crates/bevy_transform/src/systems.rs index 4935d05f8f..f41fc50bd3 100644 --- a/crates/bevy_transform/src/systems.rs +++ b/crates/bevy_transform/src/systems.rs @@ -1,4 +1,5 @@ use crate::components::{GlobalTransform, Transform}; +use alloc::vec::Vec; use bevy_ecs::{ change_detection::Ref, prelude::{Changed, DetectChanges, Entity, Query, With, Without}, diff --git a/tools/ci/src/commands/compile_check_no_std.rs b/tools/ci/src/commands/compile_check_no_std.rs index ac8718ac5d..6e5864b13d 100644 --- a/tools/ci/src/commands/compile_check_no_std.rs +++ b/tools/ci/src/commands/compile_check_no_std.rs @@ -134,6 +134,14 @@ impl Prepare for CompileCheckNoStdCommand { "Please fix compiler errors in output above for bevy_state no_std compatibility.", )); + commands.push(PreparedCommand::new::( + cmd!( + sh, + "cargo check -p bevy_transform --no-default-features --features bevy-support,serialize,libm --target {target}" + ), + "Please fix compiler errors in output above for bevy_transform no_std compatibility.", + )); + commands } }