Skip to content

Commit

Permalink
Merge branch 'main' into reflect-for-input
Browse files Browse the repository at this point in the history
  • Loading branch information
jakobhellermann committed Aug 22, 2022
2 parents 655fbdd + cde5ae8 commit e6e553d
Show file tree
Hide file tree
Showing 27 changed files with 291 additions and 103 deletions.
6 changes: 3 additions & 3 deletions assets/scenes/load_scene_example.scn.ron
Expand Up @@ -6,15 +6,15 @@
"type": "bevy_transform::components::transform::Transform",
"struct": {
"translation": {
"type": "glam::vec3::Vec3",
"type": "glam::f32::vec3::Vec3",
"value": (0.0, 0.0, 0.0),
},
"rotation": {
"type": "glam::quat::Quat",
"type": "glam::f32::scalar::quat::Quat",
"value": (0.0, 0.0, 0.0, 1.0),
},
"scale": {
"type": "glam::vec3::Vec3",
"type": "glam::f32::vec3::Vec3",
"value": (1.0, 1.0, 1.0),
},
},
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_asset/src/path.rs
Expand Up @@ -154,7 +154,7 @@ impl<'a, 'b> From<&'a AssetPath<'b>> for AssetPathId {

impl<'a> From<&'a str> for AssetPath<'a> {
fn from(asset_path: &'a str) -> Self {
let mut parts = asset_path.split('#');
let mut parts = asset_path.splitn(2, '#');
let path = Path::new(parts.next().expect("Path must be set."));
let label = parts.next();
AssetPath {
Expand Down
4 changes: 3 additions & 1 deletion crates/bevy_core/src/lib.rs
Expand Up @@ -17,6 +17,7 @@ pub mod prelude {
use bevy_app::prelude::*;
use bevy_ecs::entity::Entity;
use bevy_utils::HashSet;
use std::borrow::Cow;
use std::ops::Range;

/// Adds core functionality to Apps.
Expand All @@ -43,7 +44,8 @@ fn register_rust_types(app: &mut App) {
app.register_type::<Range<f32>>()
.register_type::<String>()
.register_type::<HashSet<String>>()
.register_type::<Option<String>>();
.register_type::<Option<String>>()
.register_type::<Cow<'static, str>>();
}

fn register_math_types(app: &mut App) {
Expand Down
51 changes: 33 additions & 18 deletions crates/bevy_ecs/src/entity/mod.rs
Expand Up @@ -40,11 +40,20 @@ pub use self::serde::*;
pub use map_entities::*;

use crate::{archetype::ArchetypeId, storage::SparseSetIndex};
use std::{
convert::TryFrom,
fmt, mem,
sync::atomic::{AtomicI64, Ordering},
};
use std::{convert::TryFrom, fmt, mem, sync::atomic::Ordering};

#[cfg(target_has_atomic = "64")]
use std::sync::atomic::AtomicI64 as AtomicIdCursor;
#[cfg(target_has_atomic = "64")]
type IdCursor = i64;

/// Most modern platforms support 64-bit atomics, but some less-common platforms
/// do not. This fallback allows compilation using a 32-bit cursor instead, with
/// the caveat that some conversions may fail (and panic) at runtime.
#[cfg(not(target_has_atomic = "64"))]
use std::sync::atomic::AtomicIsize as AtomicIdCursor;
#[cfg(not(target_has_atomic = "64"))]
type IdCursor = isize;

/// Lightweight identifier of an [entity](crate::entity).
///
Expand Down Expand Up @@ -291,7 +300,7 @@ pub struct Entities {
///
/// Once `flush()` is done, `free_cursor` will equal `pending.len()`.
pending: Vec<u32>,
free_cursor: AtomicI64,
free_cursor: AtomicIdCursor,
/// Stores the number of free entities for [`len`](Entities::len)
len: u32,
}
Expand All @@ -304,8 +313,12 @@ impl Entities {
// Use one atomic subtract to grab a range of new IDs. The range might be
// entirely nonnegative, meaning all IDs come from the freelist, or entirely
// negative, meaning they are all new IDs to allocate, or a mix of both.
let range_end = self.free_cursor.fetch_sub(count as i64, Ordering::Relaxed);
let range_start = range_end - count as i64;
let range_end = self
.free_cursor
// Unwrap: these conversions can only fail on platforms that don't support 64-bit atomics
// and use AtomicIsize instead (see note on `IdCursor`).
.fetch_sub(IdCursor::try_from(count).unwrap(), Ordering::Relaxed);
let range_start = range_end - IdCursor::try_from(count).unwrap();

let freelist_range = range_start.max(0) as usize..range_end.max(0) as usize;

Expand All @@ -322,7 +335,7 @@ impl Entities {
// In this example, we truncate the end to 0, leaving us with `-3..0`.
// Then we negate these values to indicate how far beyond the end of `meta.end()`
// to go, yielding `meta.len()+0 .. meta.len()+3`.
let base = self.meta.len() as i64;
let base = self.meta.len() as IdCursor;

let new_id_end = u32::try_from(base - range_start).expect("too many entities");

Expand Down Expand Up @@ -359,7 +372,7 @@ impl Entities {
// and farther beyond `meta.len()`.
Entity {
generation: 0,
id: u32::try_from(self.meta.len() as i64 - n).expect("too many entities"),
id: u32::try_from(self.meta.len() as IdCursor - n).expect("too many entities"),
}
}
}
Expand All @@ -377,7 +390,7 @@ impl Entities {
self.verify_flushed();
self.len += 1;
if let Some(id) = self.pending.pop() {
let new_free_cursor = self.pending.len() as i64;
let new_free_cursor = self.pending.len() as IdCursor;
*self.free_cursor.get_mut() = new_free_cursor;
Entity {
generation: self.meta[id as usize].generation,
Expand All @@ -399,14 +412,14 @@ impl Entities {

let loc = if entity.id as usize >= self.meta.len() {
self.pending.extend((self.meta.len() as u32)..entity.id);
let new_free_cursor = self.pending.len() as i64;
let new_free_cursor = self.pending.len() as IdCursor;
*self.free_cursor.get_mut() = new_free_cursor;
self.meta.resize(entity.id as usize + 1, EntityMeta::EMPTY);
self.len += 1;
None
} else if let Some(index) = self.pending.iter().position(|item| *item == entity.id) {
self.pending.swap_remove(index);
let new_free_cursor = self.pending.len() as i64;
let new_free_cursor = self.pending.len() as IdCursor;
*self.free_cursor.get_mut() = new_free_cursor;
self.len += 1;
None
Expand All @@ -430,14 +443,14 @@ impl Entities {

let result = if entity.id as usize >= self.meta.len() {
self.pending.extend((self.meta.len() as u32)..entity.id);
let new_free_cursor = self.pending.len() as i64;
let new_free_cursor = self.pending.len() as IdCursor;
*self.free_cursor.get_mut() = new_free_cursor;
self.meta.resize(entity.id as usize + 1, EntityMeta::EMPTY);
self.len += 1;
AllocAtWithoutReplacement::DidNotExist
} else if let Some(index) = self.pending.iter().position(|item| *item == entity.id) {
self.pending.swap_remove(index);
let new_free_cursor = self.pending.len() as i64;
let new_free_cursor = self.pending.len() as IdCursor;
*self.free_cursor.get_mut() = new_free_cursor;
self.len += 1;
AllocAtWithoutReplacement::DidNotExist
Expand Down Expand Up @@ -472,7 +485,7 @@ impl Entities {

self.pending.push(entity.id);

let new_free_cursor = self.pending.len() as i64;
let new_free_cursor = self.pending.len() as IdCursor;
*self.free_cursor.get_mut() = new_free_cursor;
self.len -= 1;
Some(loc)
Expand All @@ -483,7 +496,9 @@ impl Entities {
self.verify_flushed();

let freelist_size = *self.free_cursor.get_mut();
let shortfall = additional as i64 - freelist_size;
// Unwrap: these conversions can only fail on platforms that don't support 64-bit atomics
// and use AtomicIsize instead (see note on `IdCursor`).
let shortfall = IdCursor::try_from(additional).unwrap() - freelist_size;
if shortfall > 0 {
self.meta.reserve(shortfall as usize);
}
Expand Down Expand Up @@ -540,7 +555,7 @@ impl Entities {
}

fn needs_flush(&mut self) -> bool {
*self.free_cursor.get_mut() != self.pending.len() as i64
*self.free_cursor.get_mut() != self.pending.len() as IdCursor
}

/// Allocates space for entities previously reserved with `reserve_entity` or
Expand Down
29 changes: 15 additions & 14 deletions crates/bevy_ecs/src/schedule/mod.rs
Expand Up @@ -211,9 +211,10 @@ impl Schedule {
)
}

let label = stage_label.as_label();
let stage = self
.get_stage_mut::<SystemStage>(&stage_label)
.unwrap_or_else(move || stage_not_found(&stage_label.as_label()));
.get_stage_mut::<SystemStage>(label)
.unwrap_or_else(move || stage_not_found(&label));
stage.add_system(system);
self
}
Expand Down Expand Up @@ -278,14 +279,12 @@ impl Schedule {
/// Panics if `label` refers to a non-existing stage, or if it's not of type `T`.
pub fn stage<T: Stage, F: FnOnce(&mut T) -> &mut T>(
&mut self,
label: impl StageLabel,
stage_label: impl StageLabel,
func: F,
) -> &mut Self {
let stage = self.get_stage_mut::<T>(&label).unwrap_or_else(move || {
panic!(
"stage '{:?}' does not exist or is the wrong type",
label.as_label()
)
let label = stage_label.as_label();
let stage = self.get_stage_mut::<T>(label).unwrap_or_else(move || {
panic!("stage '{label:?}' does not exist or is the wrong type",)
});
func(stage);
self
Expand All @@ -304,11 +303,12 @@ impl Schedule {
/// # let mut schedule = Schedule::default();
/// # schedule.add_stage("my_stage", SystemStage::parallel());
/// #
/// let stage = schedule.get_stage::<SystemStage>(&"my_stage").unwrap();
/// let stage = schedule.get_stage::<SystemStage>("my_stage").unwrap();
/// ```
pub fn get_stage<T: Stage>(&self, label: &dyn StageLabel) -> Option<&T> {
pub fn get_stage<T: Stage>(&self, stage_label: impl StageLabel) -> Option<&T> {
let label = stage_label.as_label();
self.stages
.get(&label.as_label())
.get(&label)
.and_then(|stage| stage.downcast_ref::<T>())
}

Expand All @@ -325,11 +325,12 @@ impl Schedule {
/// # let mut schedule = Schedule::default();
/// # schedule.add_stage("my_stage", SystemStage::parallel());
/// #
/// let stage = schedule.get_stage_mut::<SystemStage>(&"my_stage").unwrap();
/// let stage = schedule.get_stage_mut::<SystemStage>("my_stage").unwrap();
/// ```
pub fn get_stage_mut<T: Stage>(&mut self, label: &dyn StageLabel) -> Option<&mut T> {
pub fn get_stage_mut<T: Stage>(&mut self, stage_label: impl StageLabel) -> Option<&mut T> {
let label = stage_label.as_label();
self.stages
.get_mut(&label.as_label())
.get_mut(&label)
.and_then(|stage| stage.downcast_mut::<T>())
}

Expand Down
1 change: 1 addition & 0 deletions crates/bevy_ecs/src/system/mod.rs
Expand Up @@ -59,6 +59,7 @@
//! - [`NonSendMut`] and `Option<NonSendMut>`
//! - [`&World`](crate::world::World)
//! - [`RemovedComponents`]
//! - [`SystemName`]
//! - [`SystemChangeTick`]
//! - [`Archetypes`](crate::archetype::Archetypes) (Provides Archetype metadata)
//! - [`Bundles`](crate::bundle::Bundles) (Provides Bundles metadata)
Expand Down
86 changes: 86 additions & 0 deletions crates/bevy_ecs/src/system/system_param.rs
Expand Up @@ -16,6 +16,7 @@ pub use bevy_ecs_macros::SystemParam;
use bevy_ecs_macros::{all_tuples, impl_param_set};
use bevy_ptr::UnsafeCellDeref;
use std::{
borrow::Cow,
fmt::Debug,
marker::PhantomData,
ops::{Deref, DerefMut},
Expand Down Expand Up @@ -1304,6 +1305,91 @@ impl<'w, 's> SystemParamFetch<'w, 's> for SystemChangeTickState {
}
}

/// Name of the system that corresponds to this [`crate::system::SystemState`].
///
/// This is not a reliable identifier, it is more so useful for debugging
/// purposes of finding where a system parameter is being used incorrectly.
pub struct SystemName<'s> {
name: &'s str,
}

impl<'s> SystemName<'s> {
pub fn name(&self) -> &str {
self.name
}
}

impl<'s> Deref for SystemName<'s> {
type Target = str;
fn deref(&self) -> &Self::Target {
self.name()
}
}

impl<'s> AsRef<str> for SystemName<'s> {
fn as_ref(&self) -> &str {
self.name()
}
}

impl<'s> From<SystemName<'s>> for &'s str {
fn from(name: SystemName<'s>) -> &'s str {
name.name
}
}

impl<'s> std::fmt::Debug for SystemName<'s> {
#[inline(always)]
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_tuple("SystemName").field(&self.name()).finish()
}
}

impl<'s> std::fmt::Display for SystemName<'s> {
#[inline(always)]
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
std::fmt::Display::fmt(&self.name(), f)
}
}

impl<'s> SystemParam for SystemName<'s> {
type Fetch = SystemNameState;
}

// SAFETY: Only reads internal system state
unsafe impl ReadOnlySystemParamFetch for SystemNameState {}

/// The [`SystemParamState`] of [`SystemName`].
#[doc(hidden)]
pub struct SystemNameState {
name: Cow<'static, str>,
}

// SAFETY: no component value access
unsafe impl SystemParamState for SystemNameState {
fn init(_world: &mut World, system_meta: &mut SystemMeta) -> Self {
Self {
name: system_meta.name.clone(),
}
}
}

impl<'w, 's> SystemParamFetch<'w, 's> for SystemNameState {
type Item = SystemName<'s>;

#[inline]
unsafe fn get_param(
state: &'s mut Self,
_system_meta: &SystemMeta,
_world: &'w World,
_change_tick: u32,
) -> Self::Item {
SystemName {
name: state.name.as_ref(),
}
}
}

macro_rules! impl_system_param_tuple {
($($param: ident),*) => {
impl<$($param: SystemParam),*> SystemParam for ($($param,)*) {
Expand Down
5 changes: 4 additions & 1 deletion crates/bevy_ecs/src/world/mod.rs
Expand Up @@ -1111,7 +1111,10 @@ impl World {
},
};
let result = f(self, value_mut);
assert!(!self.contains_resource::<R>());
assert!(!self.contains_resource::<R>(),
"Resource `{}` was inserted during a call to World::resource_scope.\n\
This is not allowed as the original resource is reinserted to the world after the FnOnce param is invoked.",
std::any::type_name::<R>());

let resource_archetype = self.archetypes.resource_mut();
let unique_components = resource_archetype.unique_components_mut();
Expand Down

0 comments on commit e6e553d

Please sign in to comment.