Skip to content

Commit f9e0aa2

Browse files
committed
using an associate constant of Resource to mark setup resources
1 parent 2ed1631 commit f9e0aa2

32 files changed

+162
-76
lines changed

crates/bevy_app/src/app.rs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -671,25 +671,33 @@ impl App {
671671
/// A setup resource is used at startup for plugin initialisation and configuration.
672672
/// All setup resources inserted must be consumed by a plugin and removed before the
673673
/// application is ran.
674-
pub fn insert_setup_resource<T>(&mut self, resource: T) -> &mut Self
674+
pub fn insert_setup_resource<R>(&mut self, resource: R) -> &mut Self
675675
where
676-
T: Resource,
676+
R: Resource,
677677
{
678-
self.setup_resources
679-
.insert(std::any::TypeId::of::<T>(), std::any::type_name::<T>());
680-
self.insert_resource(Setup(resource));
678+
if R::IS_SETUP_RESOURCE {
679+
self.setup_resources
680+
.insert(std::any::TypeId::of::<R>(), std::any::type_name::<R>());
681+
self.insert_resource(Setup(resource));
682+
} else {
683+
// Using `eprintln` here as this is supposed to be called before logs are set up
684+
eprintln!(
685+
"Resource {} is not a setup resource",
686+
std::any::type_name::<R>()
687+
);
688+
}
681689
self
682690
}
683691

684692
/// Consumes a setup resource, and removes it from the current [App] so that a plugin
685693
/// can use it for its setup.
686-
pub fn consume_setup_resource<T>(&mut self) -> Option<T>
694+
pub fn consume_setup_resource<R>(&mut self) -> Option<R>
687695
where
688-
T: Resource,
696+
R: Resource,
689697
{
690-
self.setup_resources.remove(&std::any::TypeId::of::<T>());
698+
self.setup_resources.remove(&std::any::TypeId::of::<R>());
691699
self.world
692-
.remove_resource::<Setup<T>>()
700+
.remove_resource::<Setup<R>>()
693701
.map(|setup| setup.0)
694702
}
695703

crates/bevy_asset/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ pub struct AssetPlugin;
6868
///
6969
/// This resource must be added before the [`AssetPlugin`] or `DefaultPlugins` to take effect.
7070
#[derive(Resource)]
71+
#[resource(setup)]
7172
pub struct AssetServerSettings {
7273
/// The base folder where assets are loaded from, relative to the executable.
7374
pub asset_folder: String,

crates/bevy_core/src/task_pool_options.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ impl TaskPoolThreadAssignmentPolicy {
3535
/// insert the default task pools into the resource map manually. If the pools are already inserted,
3636
/// this helper will do nothing.
3737
#[derive(Clone, Resource)]
38+
#[resource(setup)]
3839
pub struct DefaultTaskPoolOptions {
3940
/// If the number of physical cores is less than min_total_threads, force using
4041
/// min_total_threads

crates/bevy_ecs/macros/src/component.rs

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,6 @@ use proc_macro2::{Span, TokenStream as TokenStream2};
44
use quote::{quote, ToTokens};
55
use syn::{parse_macro_input, parse_quote, DeriveInput, Error, Ident, Path, Result};
66

7-
pub fn derive_resource(input: TokenStream) -> TokenStream {
8-
let mut ast = parse_macro_input!(input as DeriveInput);
9-
let bevy_ecs_path: Path = crate::bevy_ecs_path();
10-
11-
ast.generics
12-
.make_where_clause()
13-
.predicates
14-
.push(parse_quote! { Self: Send + Sync + 'static });
15-
16-
let struct_name = &ast.ident;
17-
let (impl_generics, type_generics, where_clause) = &ast.generics.split_for_impl();
18-
19-
TokenStream::from(quote! {
20-
impl #impl_generics #bevy_ecs_path::system::Resource for #struct_name #type_generics #where_clause {
21-
}
22-
})
23-
}
24-
257
pub fn derive_component(input: TokenStream) -> TokenStream {
268
let mut ast = parse_macro_input!(input as DeriveInput);
279
let bevy_ecs_path: Path = crate::bevy_ecs_path();

crates/bevy_ecs/macros/src/lib.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ extern crate proc_macro;
22

33
mod component;
44
mod fetch;
5+
mod resource;
56

67
use crate::fetch::derive_world_query_impl;
78
use bevy_macro_utils::{derive_label, get_named_struct_fields, BevyManifest};
@@ -496,9 +497,9 @@ pub(crate) fn bevy_ecs_path() -> syn::Path {
496497
BevyManifest::default().get_path("bevy_ecs")
497498
}
498499

499-
#[proc_macro_derive(Resource)]
500+
#[proc_macro_derive(Resource, attributes(resource))]
500501
pub fn derive_resource(input: TokenStream) -> TokenStream {
501-
component::derive_resource(input)
502+
resource::derive_resource(input)
502503
}
503504

504505
#[proc_macro_derive(Component, attributes(component))]
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
use bevy_macro_utils::Symbol;
2+
use proc_macro::TokenStream;
3+
use proc_macro2::Span;
4+
use quote::{quote, ToTokens};
5+
use syn::{parse_macro_input, parse_quote, DeriveInput, Error, Ident, Path, Result};
6+
7+
pub fn derive_resource(input: TokenStream) -> TokenStream {
8+
let mut ast = parse_macro_input!(input as DeriveInput);
9+
let bevy_ecs_path: Path = crate::bevy_ecs_path();
10+
11+
let attrs = match parse_resource_attr(&ast) {
12+
Ok(attrs) => attrs,
13+
Err(e) => return e.into_compile_error().into(),
14+
};
15+
16+
let is_setup_resource = Ident::new(&format!("{}", attrs.is_setup_resource), Span::call_site());
17+
18+
ast.generics
19+
.make_where_clause()
20+
.predicates
21+
.push(parse_quote! { Self: Send + Sync + 'static });
22+
23+
let struct_name = &ast.ident;
24+
let (impl_generics, type_generics, where_clause) = &ast.generics.split_for_impl();
25+
26+
TokenStream::from(quote! {
27+
impl #impl_generics #bevy_ecs_path::system::Resource for #struct_name #type_generics #where_clause {
28+
const IS_SETUP_RESOURCE: bool = #is_setup_resource;
29+
}
30+
})
31+
}
32+
33+
pub const RESOURCE: Symbol = Symbol("resource");
34+
pub const SETUP_RESOURCE: Symbol = Symbol("setup");
35+
36+
struct Attrs {
37+
is_setup_resource: bool,
38+
}
39+
40+
fn parse_resource_attr(ast: &DeriveInput) -> Result<Attrs> {
41+
let meta_items = bevy_macro_utils::parse_attrs(ast, RESOURCE)?;
42+
43+
let mut attrs = Attrs {
44+
is_setup_resource: false,
45+
};
46+
47+
for meta in meta_items {
48+
use syn::{
49+
Meta::Path,
50+
NestedMeta::{Lit, Meta},
51+
};
52+
match meta {
53+
Meta(Path(m)) if m == SETUP_RESOURCE => attrs.is_setup_resource = true,
54+
Meta(meta_item) => {
55+
return Err(Error::new_spanned(
56+
meta_item.path(),
57+
format!(
58+
"unknown component attribute `{}`",
59+
meta_item.path().into_token_stream()
60+
),
61+
));
62+
}
63+
Lit(lit) => {
64+
return Err(Error::new_spanned(
65+
lit,
66+
"unexpected literal in component attribute",
67+
))
68+
}
69+
}
70+
}
71+
72+
Ok(attrs)
73+
}

crates/bevy_ecs/src/system/commands/mod.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -373,9 +373,13 @@ impl<'w, 's> Commands<'w, 's> {
373373
/// # bevy_ecs::system::assert_is_system(initialise_scoreboard);
374374
/// ```
375375
pub fn init_resource<R: Resource + FromWorld>(&mut self) {
376-
self.queue.push(InitResource::<R> {
377-
_phantom: PhantomData::<R>::default(),
378-
});
376+
if !R::IS_SETUP_RESOURCE {
377+
self.queue.push(InitResource::<R> {
378+
_phantom: PhantomData::<R>::default(),
379+
});
380+
} else {
381+
error!("Initializing resource {} during execution has no effect. It should be added during setup using `insert_setup_resource`.", std::any::type_name::<R>());
382+
}
379383
}
380384

381385
/// Inserts a resource to the [`World`], overwriting any previous value of the same type.
@@ -404,7 +408,11 @@ impl<'w, 's> Commands<'w, 's> {
404408
/// # bevy_ecs::system::assert_is_system(system);
405409
/// ```
406410
pub fn insert_resource<R: Resource>(&mut self, resource: R) {
407-
self.queue.push(InsertResource { resource });
411+
if !R::IS_SETUP_RESOURCE {
412+
self.queue.push(InsertResource { resource });
413+
} else {
414+
error!("Inserting resource {} during execution has no effect. It should be added during setup using `insert_setup_resource`.", std::any::type_name::<R>());
415+
}
408416
}
409417

410418
/// Removes a resource from the [`World`].

crates/bevy_ecs/src/system/system_param.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,9 @@ impl_param_set!();
252252
/// # schedule.add_system_to_stage("update", write_resource_system.after("first"));
253253
/// # schedule.run_once(&mut world);
254254
/// ```
255-
pub trait Resource: Send + Sync + 'static {}
255+
pub trait Resource: Send + Sync + 'static {
256+
const IS_SETUP_RESOURCE: bool = false;
257+
}
256258

257259
/// Shared borrow of a [`Resource`].
258260
///

crates/bevy_ecs/src/world/mod.rs

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use crate::{
2121
system::Resource,
2222
};
2323
use bevy_ptr::{OwningPtr, Ptr, UnsafeCellDeref};
24-
use bevy_utils::tracing::debug;
24+
use bevy_utils::tracing::{debug, error};
2525
use std::{
2626
any::TypeId,
2727
fmt,
@@ -659,13 +659,20 @@ impl World {
659659
/// you will overwrite any existing data.
660660
#[inline]
661661
pub fn insert_resource<R: Resource>(&mut self, value: R) {
662-
let component_id = self.components.init_resource::<R>();
663-
OwningPtr::make(value, |ptr| {
664-
// SAFETY: component_id was just initialized and corresponds to resource of type R
665-
unsafe {
666-
self.insert_resource_by_id(component_id, ptr);
667-
}
668-
});
662+
if !R::IS_SETUP_RESOURCE {
663+
let component_id = self.components.init_resource::<R>();
664+
OwningPtr::make(value, |ptr| {
665+
// SAFETY: component_id was just initialized and corresponds to resource of type R
666+
unsafe {
667+
self.insert_resource_by_id(component_id, ptr);
668+
}
669+
});
670+
} else {
671+
error!(
672+
"Inserting setup resource {} as a normal resource, ignoring",
673+
std::any::type_name::<R>()
674+
);
675+
}
669676
}
670677

671678
/// Inserts a new non-send resource with standard starting values.

crates/bevy_log/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ pub struct LogPlugin;
9292

9393
/// `LogPlugin` settings
9494
#[derive(Resource)]
95+
#[resource(setup)]
9596
pub struct LogSettings {
9697
/// Filters logs using the [`EnvFilter`] format
9798
pub filter: String,

crates/bevy_render/src/texture/image.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ impl ImageSampler {
162162
///
163163
/// Can be set via `insert_setup_resource` during app initialization to change the default settings.
164164
#[derive(Resource)]
165+
#[resource(setup)]
165166
pub struct ImageSettings {
166167
/// The default image sampler to use when [`ImageSampler`] is set to `Default`.
167168
pub default_sampler: wgpu::SamplerDescriptor<'static>,

crates/bevy_window/src/event.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::path::PathBuf;
22

3-
use super::{WindowId, WindowSetupDescriptor};
3+
use super::{WindowDescriptor, WindowId};
44
use bevy_math::{IVec2, Vec2};
55

66
/// A window event that is sent whenever a window's logical size has changed.
@@ -17,7 +17,7 @@ pub struct WindowResized {
1717
#[derive(Debug, Clone)]
1818
pub struct CreateWindow {
1919
pub id: WindowId,
20-
pub descriptor: WindowSetupDescriptor,
20+
pub descriptor: WindowDescriptor,
2121
}
2222

2323
/// An event that indicates the window should redraw, even if its control flow is set to `Wait` and

crates/bevy_window/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub mod prelude {
1717
#[doc(hidden)]
1818
pub use crate::{
1919
CursorEntered, CursorIcon, CursorLeft, CursorMoved, FileDragAndDrop, MonitorSelection,
20-
ReceivedCharacter, Window, WindowMode, WindowMoved, WindowPosition, WindowSetupDescriptor,
20+
ReceivedCharacter, Window, WindowDescriptor, WindowMode, WindowMoved, WindowPosition,
2121
Windows,
2222
};
2323
}
@@ -99,7 +99,7 @@ impl Plugin for WindowPlugin {
9999

100100
if settings.add_primary_window {
101101
let window_descriptor = app
102-
.consume_setup_resource::<WindowSetupDescriptor>()
102+
.consume_setup_resource::<WindowDescriptor>()
103103
.unwrap_or_default();
104104
let mut create_window_event = app.world.resource_mut::<Events<CreateWindow>>();
105105
create_window_event.send(CreateWindow {

crates/bevy_window/src/window.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pub struct WindowId(Uuid);
2121
/// `Immediate` or `Mailbox` will gracefully fallback to `Fifo` when unavailable.
2222
///
2323
/// The presentation mode may be declared in the
24-
/// [`WindowSetupDescriptor`](WindowSetupDescriptor::present_mode) or updated on a
24+
/// [`WindowDescriptor`](WindowDescriptor::present_mode) or updated on a
2525
/// [`Window`](Window::set_present_mode).
2626
#[repr(C)]
2727
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
@@ -306,7 +306,7 @@ impl Window {
306306
/// Creates a new [`Window`].
307307
pub fn new(
308308
id: WindowId,
309-
window_descriptor: &WindowSetupDescriptor,
309+
window_descriptor: &WindowDescriptor,
310310
physical_width: u32,
311311
physical_height: u32,
312312
scale_factor: f64,
@@ -752,13 +752,13 @@ pub enum WindowPosition {
752752
Automatic,
753753
/// Center the window on the monitor.
754754
///
755-
/// The monitor to center the window on can be selected with the `monitor` field in `WindowSetupDescriptor`.
755+
/// The monitor to center the window on can be selected with the `monitor` field in `WindowDescriptor`.
756756
Centered,
757757
/// The window's top-left corner will be placed at the specified position in pixels.
758758
///
759759
/// (0,0) represents top-left corner of the monitor.
760760
///
761-
/// The monitor to position the window on can be selected with the `monitor` field in `WindowSetupDescriptor`.
761+
/// The monitor to position the window on can be selected with the `monitor` field in `WindowDescriptor`.
762762
At(Vec2),
763763
}
764764

@@ -784,7 +784,8 @@ pub enum MonitorSelection {
784784
///
785785
/// [`examples/window/window_settings.rs`]: https://github.com/bevyengine/bevy/blob/latest/examples/window/window_settings.rs
786786
#[derive(Resource, Debug, Clone)]
787-
pub struct WindowSetupDescriptor {
787+
#[resource(setup)]
788+
pub struct WindowDescriptor {
788789
/// The requested logical width of the window's client area.
789790
///
790791
/// May vary from the physical width due to different pixel density on different monitors.
@@ -862,9 +863,9 @@ pub struct WindowSetupDescriptor {
862863
pub fit_canvas_to_parent: bool,
863864
}
864865

865-
impl Default for WindowSetupDescriptor {
866+
impl Default for WindowDescriptor {
866867
fn default() -> Self {
867-
WindowSetupDescriptor {
868+
WindowDescriptor {
868869
title: "app".to_string(),
869870
width: 1280.,
870871
height: 720.,

crates/bevy_winit/src/winit_windows.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use bevy_math::{DVec2, IVec2};
22
use bevy_utils::HashMap;
3-
use bevy_window::{MonitorSelection, Window, WindowId, WindowMode, WindowSetupDescriptor};
3+
use bevy_window::{MonitorSelection, Window, WindowDescriptor, WindowId, WindowMode};
44
use raw_window_handle::HasRawWindowHandle;
55
use winit::{
66
dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize},
@@ -23,11 +23,11 @@ impl WinitWindows {
2323
&mut self,
2424
event_loop: &winit::event_loop::EventLoopWindowTarget<()>,
2525
window_id: WindowId,
26-
window_descriptor: &WindowSetupDescriptor,
26+
window_descriptor: &WindowDescriptor,
2727
) -> Window {
2828
let mut winit_window_builder = winit::window::WindowBuilder::new();
2929

30-
let &WindowSetupDescriptor {
30+
let &WindowDescriptor {
3131
width,
3232
height,
3333
position,

examples/ios/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use bevy::{input::touch::TouchPhase, prelude::*, window::WindowMode};
44
#[bevy_main]
55
fn main() {
66
App::new()
7-
.insert_setup_resource(WindowSetupDescriptor {
7+
.insert_setup_resource(WindowDescriptor {
88
resizable: false,
99
mode: WindowMode::BorderlessFullscreen,
1010
..default()

0 commit comments

Comments
 (0)