bevy/crates/bevy_reflect/derive/src/impls/common.rs
Zachary Harrold bf765e61b5
Add no_std support to bevy_reflect (#16256)
# Objective

- Contributes to #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 <49806985+MrGVSV@users.noreply.github.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-12-05 21:15:21 +00:00

159 lines
5.1 KiB
Rust

use bevy_macro_utils::fq_std::{FQAny, FQOption, FQResult};
use quote::quote;
use crate::{derive_data::ReflectMeta, where_clause_options::WhereClauseOptions};
pub fn impl_full_reflect(
meta: &ReflectMeta,
where_clause_options: &WhereClauseOptions,
) -> proc_macro2::TokenStream {
let bevy_reflect_path = meta.bevy_reflect_path();
let type_path = meta.type_path();
let (impl_generics, ty_generics, where_clause) = type_path.generics().split_for_impl();
let where_reflect_clause = where_clause_options.extend_where_clause(where_clause);
let any_impls = if meta.is_remote_wrapper() {
quote! {
#[inline]
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]
fn as_any(&self) -> &dyn #FQAny {
&self.0
}
#[inline]
fn as_any_mut(&mut self) -> &mut dyn #FQAny {
&mut self.0
}
}
} else {
quote! {
#[inline]
fn into_any(self: #bevy_reflect_path::__macro_exports::alloc_utils::Box<Self>) -> #bevy_reflect_path::__macro_exports::alloc_utils::Box<dyn #FQAny> {
self
}
#[inline]
fn as_any(&self) -> &dyn #FQAny {
self
}
#[inline]
fn as_any_mut(&mut self) -> &mut dyn #FQAny {
self
}
}
};
quote! {
impl #impl_generics #bevy_reflect_path::Reflect for #type_path #ty_generics #where_reflect_clause {
#any_impls
#[inline]
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
}
#[inline]
fn as_reflect(&self) -> &dyn #bevy_reflect_path::Reflect {
self
}
#[inline]
fn as_reflect_mut(&mut self) -> &mut dyn #bevy_reflect_path::Reflect {
self
}
#[inline]
fn set(
&mut self,
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(())
}
}
}
}
pub fn common_partial_reflect_methods(
meta: &ReflectMeta,
default_partial_eq_delegate: impl FnOnce() -> Option<proc_macro2::TokenStream>,
default_hash_delegate: impl FnOnce() -> Option<proc_macro2::TokenStream>,
) -> proc_macro2::TokenStream {
let bevy_reflect_path = meta.bevy_reflect_path();
let debug_fn = meta.attrs().get_debug_impl();
let partial_eq_fn = meta
.attrs()
.get_partial_eq_impl(bevy_reflect_path)
.or_else(move || {
let default_delegate = default_partial_eq_delegate();
default_delegate.map(|func| {
quote! {
fn reflect_partial_eq(&self, value: &dyn #bevy_reflect_path::PartialReflect) -> #FQOption<bool> {
(#func)(self, value)
}
}
})
});
let hash_fn = meta
.attrs()
.get_hash_impl(bevy_reflect_path)
.or_else(move || {
let default_delegate = default_hash_delegate();
default_delegate.map(|func| {
quote! {
fn reflect_hash(&self) -> #FQOption<u64> {
(#func)(self)
}
}
})
});
quote! {
#[inline]
fn try_into_reflect(
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)
}
#[inline]
fn try_as_reflect(&self) -> #FQOption<&dyn #bevy_reflect_path::Reflect> {
#FQOption::Some(self)
}
#[inline]
fn try_as_reflect_mut(&mut self) -> #FQOption<&mut dyn #bevy_reflect_path::Reflect> {
#FQOption::Some(self)
}
#[inline]
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
}
#[inline]
fn as_partial_reflect(&self) -> &dyn #bevy_reflect_path::PartialReflect {
self
}
#[inline]
fn as_partial_reflect_mut(&mut self) -> &mut dyn #bevy_reflect_path::PartialReflect {
self
}
#hash_fn
#partial_eq_fn
#debug_fn
}
}