Skip to content

Commit

Permalink
Add no_std support to bevy_reflect (bevyengine#16256)
Browse files Browse the repository at this point in the history
# Objective

- Contributes to bevyengine#15460

## Solution

- Added `std` feature (enabled by default)

## Testing

- CI
- `cargo check -p bevy_reflect --no-default-features --target
"x86_64-unknown-none"`
- UEFI demo application runs with this branch of `bevy_reflect`,
allowing `derive(Reflect)`

## Notes

- The [`spin`](https://crates.io/crates/spin) crate has been included to
provide `RwLock` and `Once` (as an alternative to `OnceLock`) when the
`std` feature is not enabled. Another alternative may be more desirable,
please provide feedback if you have a strong opinion here!
- Certain items (`Box`, `String`, `ToString`) provided by `alloc` have
been added to `__macro_exports` as a way to avoid `alloc` vs `std`
namespacing. I'm personally quite annoyed that we can't rely on `alloc`
as a crate name in `std` environments within macros. I'd love an
alternative to my approach here, but I suspect it's the least-bad
option.
- I would've liked to have an `alloc` feature (for allocation-free
`bevy_reflect`), unfortunately, `erased_serde` unconditionally requires
access to `Box`. Maybe one day we could design around this, but for now
it just means `bevy_reflect` requires `alloc`.

---------

Co-authored-by: Gino Valente <[email protected]>
Co-authored-by: Alice Cecile <[email protected]>
  • Loading branch information
3 people authored and ecoskey committed Jan 6, 2025
1 parent 02ad7d6 commit ec61768
Show file tree
Hide file tree
Showing 68 changed files with 364 additions and 143 deletions.
50 changes: 37 additions & 13 deletions crates/bevy_reflect/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,24 @@ keywords = ["bevy"]
rust-version = "1.81.0"

[features]
default = ["smallvec", "debug", "alloc"]
default = ["std", "smallvec", "debug"]
std = [
"bevy_utils/std",
"erased-serde/std",
"downcast-rs/std",
"serde/std",
"spin/std",
"glam?/std",
"smol_str?/std",
"uuid?/std",
]
# When enabled, provides Bevy-related reflection implementations
bevy = ["smallvec", "smol_str"]
glam = ["dep:glam"]
petgraph = ["dep:petgraph"]
petgraph = ["dep:petgraph", "std"]
smallvec = ["dep:smallvec"]
uuid = ["dep:uuid"]
wgpu-types = ["dep:wgpu-types"]
wgpu-types = ["dep:wgpu-types", "std"]
# Enables features useful for debugging reflection
debug = ["debug_stack"]
# When enabled, keeps track of the current serialization/deserialization context for better error messages
Expand All @@ -26,31 +36,45 @@ debug_stack = []
documentation = ["bevy_reflect_derive/documentation"]
# Enables function reflection
functions = ["bevy_reflect_derive/functions"]
alloc = []

[dependencies]
# bevy
bevy_reflect_derive = { path = "derive", version = "0.15.0-dev" }
bevy_utils = { path = "../bevy_utils", version = "0.15.0-dev" }
bevy_utils = { path = "../bevy_utils", version = "0.15.0-dev", default-features = false, features = [
"alloc",
] }
bevy_ptr = { path = "../bevy_ptr", version = "0.15.0-dev" }

# other
erased-serde = "0.4"
disqualified = "1.0"
downcast-rs = "1.2"
erased-serde = { version = "0.4", default-features = false, features = [
"alloc",
] }
disqualified = { version = "1.0", default-features = false }
downcast-rs = { version = "1.2", default-features = false }
derive_more = { version = "1", default-features = false, features = [
"error",
"from",
"display",
] }
serde = "1"
smallvec = { version = "1.11", optional = true }
serde = { version = "1", default-features = false, features = ["alloc"] }
spin = { version = "0.9.8", default-features = false, features = [
"once",
"rwlock",
] }
assert_type_match = "0.1.1"

glam = { version = "0.29", features = ["serde"], optional = true }
smallvec = { version = "1.11", default-features = false, optional = true }
glam = { version = "0.29", default-features = false, features = [
"serde",
], optional = true }
petgraph = { version = "0.6", features = ["serde-1"], optional = true }
smol_str = { version = "0.2.0", features = ["serde"], optional = true }
uuid = { version = "1.0", optional = true, features = ["v4", "serde"] }
smol_str = { version = "0.2.0", default-features = false, features = [
"serde",
], optional = true }
uuid = { version = "1.0", default-features = false, optional = true, features = [
"v4",
"serde",
] }
variadics_please = "1.0"
wgpu-types = { version = "23", features = ["serde"], optional = true }

Expand Down
9 changes: 7 additions & 2 deletions crates/bevy_reflect/derive/src/derive_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,9 +280,11 @@ impl<'a> ReflectDerive<'a> {
match &input.data {
Data::Struct(data) => {
let fields = Self::collect_struct_fields(&data.fields)?;
let serialization_data =
SerializationDataDef::new(&fields, &meta.bevy_reflect_path)?;
let reflect_struct = ReflectStruct {
meta,
serialization_data: SerializationDataDef::new(&fields)?,
serialization_data,
fields,
};

Expand Down Expand Up @@ -1034,6 +1036,7 @@ impl<'a> ReflectTypePath<'a> {
fn reduce_generics(
generics: &Generics,
mut ty_generic_fn: impl FnMut(&TypeParam) -> StringExpr,
bevy_reflect_path: &Path,
) -> StringExpr {
let mut params = generics.params.iter().filter_map(|param| match param {
GenericParam::Type(type_param) => Some(ty_generic_fn(type_param)),
Expand All @@ -1042,7 +1045,7 @@ impl<'a> ReflectTypePath<'a> {
let ty = &const_param.ty;

Some(StringExpr::Owned(quote! {
<#ty as ::std::string::ToString>::to_string(&#ident)
<#ty as #bevy_reflect_path::__macro_exports::alloc_utils::ToString>::to_string(&#ident)
}))
}
GenericParam::Lifetime(_) => None,
Expand Down Expand Up @@ -1074,6 +1077,7 @@ impl<'a> ReflectTypePath<'a> {
<#ident as #bevy_reflect_path::TypePath>::type_path()
})
},
bevy_reflect_path,
);

StringExpr::from_iter([
Expand Down Expand Up @@ -1111,6 +1115,7 @@ impl<'a> ReflectTypePath<'a> {
<#ident as #bevy_reflect_path::TypePath>::short_type_path()
})
},
bevy_reflect_path,
);

StringExpr::from_iter([
Expand Down
4 changes: 2 additions & 2 deletions crates/bevy_reflect/derive/src/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub(crate) fn generate_generics(meta: &ReflectMeta) -> Option<TokenStream> {
Some(quote! {
#bevy_reflect_path::GenericInfo::Type(
#bevy_reflect_path::TypeParamInfo::new::<#ident>(
::std::borrow::Cow::Borrowed(#name),
#bevy_reflect_path::__macro_exports::alloc_utils::Cow::Borrowed(#name),
)
#with_default
)
Expand All @@ -53,7 +53,7 @@ pub(crate) fn generate_generics(meta: &ReflectMeta) -> Option<TokenStream> {
)]
#bevy_reflect_path::GenericInfo::Const(
#bevy_reflect_path::ConstParamInfo::new::<#ty>(
::std::borrow::Cow::Borrowed(#name),
#bevy_reflect_path::__macro_exports::alloc_utils::Cow::Borrowed(#name),
)
#with_default
)
Expand Down
20 changes: 10 additions & 10 deletions crates/bevy_reflect/derive/src/impls/common.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use bevy_macro_utils::fq_std::{FQAny, FQBox, FQOption, FQResult};
use bevy_macro_utils::fq_std::{FQAny, FQOption, FQResult};

use quote::quote;

Expand All @@ -17,8 +17,8 @@ pub fn impl_full_reflect(
let any_impls = if meta.is_remote_wrapper() {
quote! {
#[inline]
fn into_any(self: #FQBox<Self>) -> #FQBox<dyn #FQAny> {
#FQBox::new(self.0)
fn into_any(self: #bevy_reflect_path::__macro_exports::alloc_utils::Box<Self>) -> #bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #FQAny> {
#bevy_reflect_path::__macro_exports::alloc_utils::Box::new(self.0)
}

#[inline]
Expand All @@ -34,7 +34,7 @@ pub fn impl_full_reflect(
} else {
quote! {
#[inline]
fn into_any(self: #FQBox<Self>) -> #FQBox<dyn #FQAny> {
fn into_any(self: #bevy_reflect_path::__macro_exports::alloc_utils::Box<Self>) -> #bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #FQAny> {
self
}

Expand All @@ -55,7 +55,7 @@ pub fn impl_full_reflect(
#any_impls

#[inline]
fn into_reflect(self: #FQBox<Self>) -> #FQBox<dyn #bevy_reflect_path::Reflect> {
fn into_reflect(self: #bevy_reflect_path::__macro_exports::alloc_utils::Box<Self>) -> #bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #bevy_reflect_path::Reflect> {
self
}

Expand All @@ -72,8 +72,8 @@ pub fn impl_full_reflect(
#[inline]
fn set(
&mut self,
value: #FQBox<dyn #bevy_reflect_path::Reflect>
) -> #FQResult<(), #FQBox<dyn #bevy_reflect_path::Reflect>> {
value: #bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #bevy_reflect_path::Reflect>
) -> #FQResult<(), #bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #bevy_reflect_path::Reflect>> {
*self = <dyn #bevy_reflect_path::Reflect>::take(value)?;
#FQResult::Ok(())
}
Expand Down Expand Up @@ -119,8 +119,8 @@ pub fn common_partial_reflect_methods(
quote! {
#[inline]
fn try_into_reflect(
self: #FQBox<Self>
) -> #FQResult<#FQBox<dyn #bevy_reflect_path::Reflect>, #FQBox<dyn #bevy_reflect_path::PartialReflect>> {
self: #bevy_reflect_path::__macro_exports::alloc_utils::Box<Self>
) -> #FQResult<#bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #bevy_reflect_path::Reflect>, #bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #bevy_reflect_path::PartialReflect>> {
#FQResult::Ok(self)
}

Expand All @@ -135,7 +135,7 @@ pub fn common_partial_reflect_methods(
}

#[inline]
fn into_partial_reflect(self: #FQBox<Self>) -> #FQBox<dyn #bevy_reflect_path::PartialReflect> {
fn into_partial_reflect(self: #bevy_reflect_path::__macro_exports::alloc_utils::Box<Self>) -> #bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #bevy_reflect_path::PartialReflect> {
self
}

Expand Down
8 changes: 4 additions & 4 deletions crates/bevy_reflect/derive/src/impls/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::{
enum_utility::{EnumVariantOutputData, TryApplyVariantBuilder, VariantBuilder},
impls::{common_partial_reflect_methods, impl_full_reflect, impl_type_path, impl_typed},
};
use bevy_macro_utils::fq_std::{FQBox, FQOption, FQResult};
use bevy_macro_utils::fq_std::{FQOption, FQResult};
use proc_macro2::{Ident, Span};
use quote::quote;
use syn::{Fields, Path};
Expand Down Expand Up @@ -186,8 +186,8 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> proc_macro2::TokenStream
}

#[inline]
fn clone_value(&self) -> #FQBox<dyn #bevy_reflect_path::PartialReflect> {
#FQBox::new(#bevy_reflect_path::Enum::clone_dynamic(self))
fn clone_value(&self) -> #bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #bevy_reflect_path::PartialReflect> {
#bevy_reflect_path::__macro_exports::alloc_utils::Box::new(#bevy_reflect_path::Enum::clone_dynamic(self))
}

#[inline]
Expand Down Expand Up @@ -256,7 +256,7 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> proc_macro2::TokenStream
#bevy_reflect_path::ReflectMut::Enum(self)
}

fn reflect_owned(self: #FQBox<Self>) -> #bevy_reflect_path::ReflectOwned {
fn reflect_owned(self: #bevy_reflect_path::__macro_exports::alloc_utils::Box<Self>) -> #bevy_reflect_path::ReflectOwned {
#bevy_reflect_path::ReflectOwned::Enum(self)
}

Expand Down
8 changes: 4 additions & 4 deletions crates/bevy_reflect/derive/src/impls/opaque.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::{
where_clause_options::WhereClauseOptions,
ReflectMeta,
};
use bevy_macro_utils::fq_std::{FQBox, FQClone, FQOption, FQResult};
use bevy_macro_utils::fq_std::{FQClone, FQOption, FQResult};
use quote::quote;

/// Implements `GetTypeRegistration` and `Reflect` for the given type data.
Expand Down Expand Up @@ -77,8 +77,8 @@ pub(crate) fn impl_opaque(meta: &ReflectMeta) -> proc_macro2::TokenStream {
}

#[inline]
fn clone_value(&self) -> #FQBox<dyn #bevy_reflect_path::PartialReflect> {
#FQBox::new(#FQClone::clone(self))
fn clone_value(&self) -> #bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #bevy_reflect_path::PartialReflect> {
#bevy_reflect_path::__macro_exports::alloc_utils::Box::new(#FQClone::clone(self))
}

#[inline]
Expand Down Expand Up @@ -112,7 +112,7 @@ pub(crate) fn impl_opaque(meta: &ReflectMeta) -> proc_macro2::TokenStream {
}

#[inline]
fn reflect_owned(self: #FQBox<Self>) -> #bevy_reflect_path::ReflectOwned {
fn reflect_owned(self: #bevy_reflect_path::__macro_exports::alloc_utils::Box<Self>) -> #bevy_reflect_path::ReflectOwned {
#bevy_reflect_path::ReflectOwned::Opaque(self)
}

Expand Down
8 changes: 4 additions & 4 deletions crates/bevy_reflect/derive/src/impls/structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::{
struct_utility::FieldAccessors,
ReflectStruct,
};
use bevy_macro_utils::fq_std::{FQBox, FQDefault, FQOption, FQResult};
use bevy_macro_utils::fq_std::{FQDefault, FQOption, FQResult};
use quote::{quote, ToTokens};

/// Implements `Struct`, `GetTypeRegistration`, and `Reflect` for the given derive data.
Expand Down Expand Up @@ -134,8 +134,8 @@ pub(crate) fn impl_struct(reflect_struct: &ReflectStruct) -> proc_macro2::TokenS
}

#[inline]
fn clone_value(&self) -> #FQBox<dyn #bevy_reflect_path::PartialReflect> {
#FQBox::new(#bevy_reflect_path::Struct::clone_dynamic(self))
fn clone_value(&self) -> #bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #bevy_reflect_path::PartialReflect> {
#bevy_reflect_path::__macro_exports::alloc_utils::Box::new(#bevy_reflect_path::Struct::clone_dynamic(self))
}

#[inline]
Expand Down Expand Up @@ -174,7 +174,7 @@ pub(crate) fn impl_struct(reflect_struct: &ReflectStruct) -> proc_macro2::TokenS
#bevy_reflect_path::ReflectMut::Struct(self)
}
#[inline]
fn reflect_owned(self: #FQBox<Self>) -> #bevy_reflect_path::ReflectOwned {
fn reflect_owned(self: #bevy_reflect_path::__macro_exports::alloc_utils::Box<Self>) -> #bevy_reflect_path::ReflectOwned {
#bevy_reflect_path::ReflectOwned::Struct(self)
}

Expand Down
8 changes: 4 additions & 4 deletions crates/bevy_reflect/derive/src/impls/tuple_structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::{
struct_utility::FieldAccessors,
ReflectStruct,
};
use bevy_macro_utils::fq_std::{FQBox, FQDefault, FQOption, FQResult};
use bevy_macro_utils::fq_std::{FQDefault, FQOption, FQResult};
use quote::{quote, ToTokens};

/// Implements `TupleStruct`, `GetTypeRegistration`, and `Reflect` for the given derive data.
Expand Down Expand Up @@ -100,8 +100,8 @@ pub(crate) fn impl_tuple_struct(reflect_struct: &ReflectStruct) -> proc_macro2::
#FQOption::Some(<Self as #bevy_reflect_path::Typed>::type_info())
}
#[inline]
fn clone_value(&self) -> #FQBox<dyn #bevy_reflect_path::PartialReflect> {
#FQBox::new(#bevy_reflect_path::TupleStruct::clone_dynamic(self))
fn clone_value(&self) -> #bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #bevy_reflect_path::PartialReflect> {
#bevy_reflect_path::__macro_exports::alloc_utils::Box::new(#bevy_reflect_path::TupleStruct::clone_dynamic(self))
}

#[inline]
Expand Down Expand Up @@ -139,7 +139,7 @@ pub(crate) fn impl_tuple_struct(reflect_struct: &ReflectStruct) -> proc_macro2::
#bevy_reflect_path::ReflectMut::TupleStruct(self)
}
#[inline]
fn reflect_owned(self: #FQBox<Self>) -> #bevy_reflect_path::ReflectOwned {
fn reflect_owned(self: #bevy_reflect_path::__macro_exports::alloc_utils::Box<Self>) -> #bevy_reflect_path::ReflectOwned {
#bevy_reflect_path::ReflectOwned::TupleStruct(self)
}

Expand Down
39 changes: 23 additions & 16 deletions crates/bevy_reflect/derive/src/impls/typed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,27 +106,34 @@ pub(crate) fn impl_type_path(meta: &ReflectMeta) -> TokenStream {
quote! {
#primitive_assert

impl #impl_generics #bevy_reflect_path::TypePath for #type_path #ty_generics #where_reflect_clause {
fn type_path() -> &'static str {
#long_type_path
}
// To ensure alloc is available, but also prevent its name from clashing, we place the implementation inside an anonymous constant
const _: () = {
extern crate alloc;

fn short_type_path() -> &'static str {
#short_type_path
}
use alloc::string::ToString;

fn type_ident() -> Option<&'static str> {
#type_ident
}
impl #impl_generics #bevy_reflect_path::TypePath for #type_path #ty_generics #where_reflect_clause {
fn type_path() -> &'static str {
#long_type_path
}

fn crate_name() -> Option<&'static str> {
#crate_name
}
fn short_type_path() -> &'static str {
#short_type_path
}

fn module_path() -> Option<&'static str> {
#module_path
fn type_ident() -> Option<&'static str> {
#type_ident
}

fn crate_name() -> Option<&'static str> {
#crate_name
}

fn module_path() -> Option<&'static str> {
#module_path
}
}
}
};
}
}

Expand Down
Loading

0 comments on commit ec61768

Please sign in to comment.