Skip to content

Commit 4bd9b8b

Browse files
committed
Make all labels internable
1 parent ea5d2d8 commit 4bd9b8b

File tree

6 files changed

+41
-210
lines changed

6 files changed

+41
-210
lines changed

crates/bevy_app/src/app.rs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use bevy_ecs::{
88
ScheduleLabel,
99
},
1010
};
11-
use bevy_utils::{tracing::debug, HashMap, HashSet};
11+
use bevy_utils::{intern::Interned, tracing::debug, HashMap, HashSet};
1212
use std::{
1313
fmt::Debug,
1414
panic::{catch_unwind, resume_unwind, AssertUnwindSafe},
@@ -20,10 +20,12 @@ use bevy_utils::tracing::info_span;
2020
bevy_utils::define_label!(
2121
/// A strongly-typed class of labels used to identify an [`App`].
2222
AppLabel,
23-
/// A strongly-typed identifier for an [`AppLabel`].
24-
AppLabelId,
23+
APP_LABEL_INTERNER
2524
);
2625

26+
/// A shorthand for `Interned<dyn AppLabel>`.
27+
pub type InternedAppLabel = Interned<dyn AppLabel>;
28+
2729
pub(crate) enum AppError {
2830
DuplicatePlugin { plugin_name: String },
2931
}
@@ -71,7 +73,7 @@ pub struct App {
7173
///
7274
/// This is initially set to [`Main`].
7375
pub main_schedule_label: InternedScheduleLabel,
74-
sub_apps: HashMap<AppLabelId, SubApp>,
76+
sub_apps: HashMap<InternedAppLabel, SubApp>,
7577
plugin_registry: Vec<Box<dyn Plugin>>,
7678
plugin_name_added: HashSet<String>,
7779
/// A private counter to prevent incorrect calls to `App::run()` from `Plugin::build()`
@@ -748,16 +750,15 @@ impl App {
748750
pub fn sub_app_mut(&mut self, label: impl AppLabel) -> &mut App {
749751
match self.get_sub_app_mut(label) {
750752
Ok(app) => app,
751-
Err(label) => panic!("Sub-App with label '{:?}' does not exist", label.as_str()),
753+
Err(label) => panic!("Sub-App with label '{:?}' does not exist", label),
752754
}
753755
}
754756

755757
/// Retrieves a `SubApp` inside this [`App`] with the given label, if it exists. Otherwise returns
756758
/// an [`Err`] containing the given label.
757-
pub fn get_sub_app_mut(&mut self, label: impl AppLabel) -> Result<&mut App, AppLabelId> {
758-
let label = label.as_label();
759+
pub fn get_sub_app_mut(&mut self, label: impl AppLabel) -> Result<&mut App, impl AppLabel> {
759760
self.sub_apps
760-
.get_mut(&label)
761+
.get_mut(&InternedAppLabel::from(&label as &dyn AppLabel))
761762
.map(|sub_app| &mut sub_app.app)
762763
.ok_or(label)
763764
}
@@ -770,25 +771,27 @@ impl App {
770771
pub fn sub_app(&self, label: impl AppLabel) -> &App {
771772
match self.get_sub_app(label) {
772773
Ok(app) => app,
773-
Err(label) => panic!("Sub-App with label '{:?}' does not exist", label.as_str()),
774+
Err(label) => panic!("Sub-App with label '{:?}' does not exist", label),
774775
}
775776
}
776777

777778
/// Inserts an existing sub app into the app
778779
pub fn insert_sub_app(&mut self, label: impl AppLabel, sub_app: SubApp) {
779-
self.sub_apps.insert(label.as_label(), sub_app);
780+
self.sub_apps
781+
.insert((&label as &dyn AppLabel).into(), sub_app);
780782
}
781783

782784
/// Removes a sub app from the app. Returns [`None`] if the label doesn't exist.
783785
pub fn remove_sub_app(&mut self, label: impl AppLabel) -> Option<SubApp> {
784-
self.sub_apps.remove(&label.as_label())
786+
self.sub_apps
787+
.remove(&InternedAppLabel::from(&label as &dyn AppLabel))
785788
}
786789

787790
/// Retrieves a `SubApp` inside this [`App`] with the given label, if it exists. Otherwise returns
788791
/// an [`Err`] containing the given label.
789792
pub fn get_sub_app(&self, label: impl AppLabel) -> Result<&App, impl AppLabel> {
790793
self.sub_apps
791-
.get(&label.as_label())
794+
.get(&InternedAppLabel::from(&label as &dyn AppLabel))
792795
.map(|sub_app| &sub_app.app)
793796
.ok_or(label)
794797
}

crates/bevy_derive/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,10 +203,10 @@ pub fn derive_enum_variant_meta(input: TokenStream) -> TokenStream {
203203
///
204204
/// This works only for unit structs, or enums with only unit variants.
205205
/// You may force a struct or variant to behave as if it were fieldless with `#[app_label(ignore_fields)]`.
206-
#[proc_macro_derive(AppLabel, attributes(app_label))]
206+
#[proc_macro_derive(AppLabel)]
207207
pub fn derive_app_label(input: TokenStream) -> TokenStream {
208208
let input = syn::parse_macro_input!(input as syn::DeriveInput);
209209
let mut trait_path = BevyManifest::default().get_path("bevy_app");
210210
trait_path.segments.push(format_ident!("AppLabel").into());
211-
derive_label(input, &trait_path, "app_label")
211+
derive_label(input, &trait_path)
212212
}

crates/bevy_ecs/macros/src/lib.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@ mod set;
66
mod states;
77

88
use crate::{fetch::derive_world_query_impl, set::derive_set};
9-
use bevy_macro_utils::{
10-
derive_interned_label, ensure_no_collision, get_named_struct_fields, BevyManifest,
11-
};
9+
use bevy_macro_utils::{derive_label, ensure_no_collision, get_named_struct_fields, BevyManifest};
1210
use proc_macro::TokenStream;
1311
use proc_macro2::Span;
1412
use quote::{format_ident, quote};
@@ -435,7 +433,7 @@ pub fn derive_schedule_label(input: TokenStream) -> TokenStream {
435433
trait_path
436434
.segments
437435
.push(format_ident!("ScheduleLabel").into());
438-
derive_interned_label(input, &trait_path)
436+
derive_label(input, &trait_path)
439437
}
440438

441439
/// Derive macro generating an impl of the trait `SystemSet`.

crates/bevy_ecs/src/schedule/set.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,19 @@ use std::hash::{Hash, Hasher};
55
use std::marker::PhantomData;
66

77
pub use bevy_ecs_macros::{ScheduleLabel, SystemSet};
8-
use bevy_utils::define_interned_label;
8+
use bevy_utils::define_label;
99
use bevy_utils::intern::{Interned, Leak, OptimizedInterner, StaticRef};
1010
use bevy_utils::label::DynHash;
1111

1212
use crate::system::{
1313
ExclusiveSystemParamFunction, IsExclusiveFunctionSystem, IsFunctionSystem, SystemParamFunction,
1414
};
1515

16-
define_interned_label!(ScheduleLabel, SCHEDULE_LABEL_INTERNER);
16+
define_label!(
17+
/// A strongly-typed class of labels used to identify an [`Schedule`].
18+
ScheduleLabel,
19+
SCHEDULE_LABEL_INTERNER
20+
);
1721

1822
static SYSTEM_SET_INTERNER: OptimizedInterner<dyn SystemSet> = OptimizedInterner::new();
1923
/// A shorthand for `Interned<dyn SystemSet>`.
@@ -248,7 +252,7 @@ mod tests {
248252
use super::*;
249253

250254
#[test]
251-
fn test_interned_label() {
255+
fn test_label() {
252256
use crate::{self as bevy_ecs, world::World};
253257

254258
#[derive(Resource)]

crates/bevy_macro_utils/src/lib.rs

Lines changed: 1 addition & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ pub fn ensure_no_collision(value: Ident, haystack: TokenStream) -> Ident {
169169
///
170170
/// - `input`: The [`syn::DeriveInput`] for struct that is deriving the label trait
171171
/// - `trait_path`: The path [`syn::Path`] to the label trait
172-
pub fn derive_interned_label(input: syn::DeriveInput, trait_path: &syn::Path) -> TokenStream {
172+
pub fn derive_label(input: syn::DeriveInput, trait_path: &syn::Path) -> TokenStream {
173173
let bevy_utils_path = BevyManifest::default().get_path("bevy_utils");
174174

175175
let ident = input.ident;
@@ -260,115 +260,3 @@ pub fn derive_interned_label(input: syn::DeriveInput, trait_path: &syn::Path) ->
260260
})
261261
.into()
262262
}
263-
264-
/// Derive a label trait
265-
///
266-
/// # Args
267-
///
268-
/// - `input`: The [`syn::DeriveInput`] for struct that is deriving the label trait
269-
/// - `trait_path`: The path [`syn::Path`] to the label trait
270-
pub fn derive_label(
271-
input: syn::DeriveInput,
272-
trait_path: &syn::Path,
273-
attr_name: &str,
274-
) -> TokenStream {
275-
// return true if the variant specified is an `ignore_fields` attribute
276-
fn is_ignore(attr: &syn::Attribute, attr_name: &str) -> bool {
277-
if attr.path().get_ident().as_ref().unwrap() != &attr_name {
278-
return false;
279-
}
280-
281-
syn::custom_keyword!(ignore_fields);
282-
attr.parse_args_with(|input: syn::parse::ParseStream| {
283-
let ignore = input.parse::<Option<ignore_fields>>()?.is_some();
284-
Ok(ignore)
285-
})
286-
.unwrap()
287-
}
288-
289-
let ident = input.ident.clone();
290-
291-
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
292-
let mut where_clause = where_clause.cloned().unwrap_or_else(|| syn::WhereClause {
293-
where_token: Default::default(),
294-
predicates: Default::default(),
295-
});
296-
where_clause
297-
.predicates
298-
.push(syn::parse2(quote! { Self: 'static }).unwrap());
299-
300-
let as_str = match input.data {
301-
syn::Data::Struct(d) => {
302-
// see if the user tried to ignore fields incorrectly
303-
if let Some(attr) = d
304-
.fields
305-
.iter()
306-
.flat_map(|f| &f.attrs)
307-
.find(|a| is_ignore(a, attr_name))
308-
{
309-
let err_msg = format!("`#[{attr_name}(ignore_fields)]` cannot be applied to fields individually: add it to the struct declaration");
310-
return quote_spanned! {
311-
attr.span() => compile_error!(#err_msg);
312-
}
313-
.into();
314-
}
315-
// Structs must either be fieldless, or explicitly ignore the fields.
316-
let ignore_fields = input.attrs.iter().any(|a| is_ignore(a, attr_name));
317-
if matches!(d.fields, syn::Fields::Unit) || ignore_fields {
318-
let lit = ident.to_string();
319-
quote! { #lit }
320-
} else {
321-
let err_msg = format!("Labels cannot contain data, unless explicitly ignored with `#[{attr_name}(ignore_fields)]`");
322-
return quote_spanned! {
323-
d.fields.span() => compile_error!(#err_msg);
324-
}
325-
.into();
326-
}
327-
}
328-
syn::Data::Enum(d) => {
329-
// check if the user put #[label(ignore_fields)] in the wrong place
330-
if let Some(attr) = input.attrs.iter().find(|a| is_ignore(a, attr_name)) {
331-
let err_msg = format!("`#[{attr_name}(ignore_fields)]` can only be applied to enum variants or struct declarations");
332-
return quote_spanned! {
333-
attr.span() => compile_error!(#err_msg);
334-
}
335-
.into();
336-
}
337-
let arms = d.variants.iter().map(|v| {
338-
// Variants must either be fieldless, or explicitly ignore the fields.
339-
let ignore_fields = v.attrs.iter().any(|a| is_ignore(a, attr_name));
340-
if matches!(v.fields, syn::Fields::Unit) | ignore_fields {
341-
let mut path = syn::Path::from(ident.clone());
342-
path.segments.push(v.ident.clone().into());
343-
let lit = format!("{ident}::{}", v.ident.clone());
344-
quote! { #path { .. } => #lit }
345-
} else {
346-
let err_msg = format!("Label variants cannot contain data, unless explicitly ignored with `#[{attr_name}(ignore_fields)]`");
347-
quote_spanned! {
348-
v.fields.span() => _ => { compile_error!(#err_msg); }
349-
}
350-
}
351-
});
352-
quote! {
353-
match self {
354-
#(#arms),*
355-
}
356-
}
357-
}
358-
syn::Data::Union(_) => {
359-
return quote_spanned! {
360-
input.span() => compile_error!("Unions cannot be used as labels.");
361-
}
362-
.into();
363-
}
364-
};
365-
366-
(quote! {
367-
impl #impl_generics #trait_path for #ident #ty_generics #where_clause {
368-
fn as_str(&self) -> &'static str {
369-
#as_str
370-
}
371-
}
372-
})
373-
.into()
374-
}

crates/bevy_utils/src/label.rs

Lines changed: 14 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,22 @@ where
6565
/// # Example
6666
///
6767
/// ```
68-
/// # use bevy_utils::define_interned_label;
69-
/// define_interned_label!(MyNewLabelTrait, MY_NEW_LABEL_TRAIT_INTERNER);
68+
/// # use bevy_utils::define_label;
69+
/// define_label!(
70+
/// /// Documentation of label trait
71+
/// MyNewLabelTrait,
72+
/// MY_NEW_LABEL_TRAIT_INTERNER
73+
/// );
7074
/// ```
7175
#[macro_export]
72-
macro_rules! define_interned_label {
73-
($label_trait_name:ident, $interner_name:ident) => {
74-
/// A strongly-typed label.
76+
macro_rules! define_label {
77+
(
78+
$(#[$label_attr:meta])*
79+
$label_trait_name:ident,
80+
$interner_name:ident
81+
) => {
82+
83+
$(#[$label_attr])*
7584
pub trait $label_trait_name: 'static + Send + Sync + ::std::fmt::Debug {
7685
/// Return's the [TypeId] of this label, or the the ID of the
7786
/// wrappped label type for `Box<dyn
@@ -181,74 +190,3 @@ macro_rules! define_interned_label {
181190
}
182191
};
183192
}
184-
185-
/// Macro to define a new label trait
186-
///
187-
/// # Example
188-
///
189-
/// ```
190-
/// # use bevy_utils::define_label;
191-
/// define_label!(
192-
/// /// A class of labels.
193-
/// MyNewLabelTrait,
194-
/// /// Identifies a value that implements `MyNewLabelTrait`.
195-
/// MyNewLabelId,
196-
/// );
197-
/// ```
198-
#[macro_export]
199-
macro_rules! define_label {
200-
(
201-
$(#[$label_attr:meta])*
202-
$label_name:ident,
203-
204-
$(#[$id_attr:meta])*
205-
$id_name:ident $(,)?
206-
) => {
207-
$(#[$id_attr])*
208-
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
209-
pub struct $id_name(::core::any::TypeId, &'static str);
210-
211-
impl ::core::fmt::Debug for $id_name {
212-
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
213-
write!(f, "{}", self.1)
214-
}
215-
}
216-
217-
$(#[$label_attr])*
218-
pub trait $label_name: 'static {
219-
/// Converts this type into an opaque, strongly-typed label.
220-
fn as_label(&self) -> $id_name {
221-
let id = self.type_id();
222-
let label = self.as_str();
223-
$id_name(id, label)
224-
}
225-
/// Returns the [`TypeId`] used to differentiate labels.
226-
fn type_id(&self) -> ::core::any::TypeId {
227-
::core::any::TypeId::of::<Self>()
228-
}
229-
/// Returns the representation of this label as a string literal.
230-
///
231-
/// In cases where you absolutely need a label to be determined at runtime,
232-
/// you can use [`Box::leak`] to get a `'static` reference.
233-
fn as_str(&self) -> &'static str;
234-
}
235-
236-
impl $label_name for $id_name {
237-
fn as_label(&self) -> Self {
238-
*self
239-
}
240-
fn type_id(&self) -> ::core::any::TypeId {
241-
self.0
242-
}
243-
fn as_str(&self) -> &'static str {
244-
self.1
245-
}
246-
}
247-
248-
impl $label_name for &'static str {
249-
fn as_str(&self) -> Self {
250-
self
251-
}
252-
}
253-
};
254-
}

0 commit comments

Comments
 (0)