Skip to content

Commit

Permalink
Modify derive_label to support no_std environments (#15465)
Browse files Browse the repository at this point in the history
# Objective

- Contributes to #15460

## Solution

- Wrap `derive_label` `quote!` in an anonymous constant which contains
an `extern crate alloc` statement, allowing use of the `alloc` namespace
even when a user has not brought in the crate themselves.

## Testing

- CI passed locally.

## Notes

We can't generate code that uses `::std::boxed::Box` in `no_std`
environments, but we also can't rely on `::alloc::boxed::Box` either,
since the user might not have declared `extern crate alloc`. To resolve
this, the generated code is wrapped in an anonymous constant which
contains the `extern crate alloc` invocation.

This does mean the macro is no longer hygienic against cases where the
user provides an alternate `alloc` crate, however I believe this is an
acceptable compromise.

Additionally, this crate itself doesn't need to be `no_std`, it just
needs to _generate_ `no_std` compatible code.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
  • Loading branch information
bushrat011899 and alice-i-cecile authored Sep 27, 2024
1 parent 60cf7ca commit 6963b58
Showing 1 changed file with 17 additions and 12 deletions.
29 changes: 17 additions & 12 deletions crates/bevy_macro_utils/src/label.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,21 +81,26 @@ pub fn derive_label(
.unwrap(),
);
quote! {
impl #impl_generics #trait_path for #ident #ty_generics #where_clause {
fn dyn_clone(&self) -> ::std::boxed::Box<dyn #trait_path> {
::std::boxed::Box::new(::core::clone::Clone::clone(self))
}
// 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 as_dyn_eq(&self) -> &dyn #dyn_eq_path {
self
}
impl #impl_generics #trait_path for #ident #ty_generics #where_clause {
fn dyn_clone(&self) -> alloc::boxed::Box<dyn #trait_path> {
alloc::boxed::Box::new(::core::clone::Clone::clone(self))
}

fn dyn_hash(&self, mut state: &mut dyn ::core::hash::Hasher) {
let ty_id = ::core::any::TypeId::of::<Self>();
::core::hash::Hash::hash(&ty_id, &mut state);
::core::hash::Hash::hash(self, &mut state);
fn as_dyn_eq(&self) -> &dyn #dyn_eq_path {
self
}

fn dyn_hash(&self, mut state: &mut dyn ::core::hash::Hasher) {
let ty_id = ::core::any::TypeId::of::<Self>();
::core::hash::Hash::hash(&ty_id, &mut state);
::core::hash::Hash::hash(self, &mut state);
}
}
}
};
}
.into()
}

0 comments on commit 6963b58

Please sign in to comment.