diff --git a/crates/bevy_core/src/bytes.rs b/crates/bevy_core/src/bytes.rs deleted file mode 100644 index 39628fc825..0000000000 --- a/crates/bevy_core/src/bytes.rs +++ /dev/null @@ -1,103 +0,0 @@ -pub use bevy_derive::Bytes; - -// NOTE: we can reexport common traits and methods from bytemuck to avoid requiring dependency most of -// the time, but unfortunately we can't use derive macros that way due to hardcoded path in generated code. -pub use bytemuck::{bytes_of, cast_slice, Pod, Zeroable}; - -// FIXME: `Bytes` trait doesn't specify the expected encoding format, -// which means types that implement it have to know what format is expected -// and can only implement one encoding at a time. -// TODO: Remove `Bytes` and `FromBytes` in favour of `crevice` crate. - -/// Converts the implementing type to bytes by writing them to a given buffer -pub trait Bytes { - /// Converts the implementing type to bytes by writing them to a given buffer - fn write_bytes(&self, buffer: &mut [u8]); - - /// The number of bytes that will be written when calling `write_bytes` - fn byte_len(&self) -> usize; -} - -impl Bytes for T -where - T: Pod, -{ - fn write_bytes(&self, buffer: &mut [u8]) { - buffer[0..self.byte_len()].copy_from_slice(bytes_of(self)) - } - - fn byte_len(&self) -> usize { - std::mem::size_of::() - } -} - -/// Converts a byte array to `Self` -pub trait FromBytes { - /// Converts a byte array to `Self` - fn from_bytes(bytes: &[u8]) -> Self; -} - -impl FromBytes for T -where - T: Pod, -{ - fn from_bytes(bytes: &[u8]) -> Self { - assert_eq!( - bytes.len(), - std::mem::size_of::(), - "Cannot convert byte slice `&[u8]` to type `{}`. They are not the same size.", - std::any::type_name::() - ); - unsafe { bytes.as_ptr().cast::().read_unaligned() } - } -} - -#[cfg(test)] -mod tests { - - use super::{Bytes, FromBytes}; - use bevy_math::{Mat4, Vec2, Vec3, Vec4}; - - fn test_round_trip(value: T) { - let mut bytes = vec![0; value.byte_len()]; - value.write_bytes(&mut bytes); - let result = T::from_bytes(&bytes); - assert_eq!(value, result); - } - - #[test] - fn test_u32_bytes_round_trip() { - test_round_trip(123u32); - } - - #[test] - fn test_f64_bytes_round_trip() { - test_round_trip(123f64); - } - - #[test] - fn test_vec2_round_trip() { - test_round_trip(Vec2::new(1.0, 2.0)); - } - - #[test] - fn test_vec3_round_trip() { - test_round_trip(Vec3::new(1.0, 2.0, 3.0)); - } - - #[test] - fn test_vec4_round_trip() { - test_round_trip(Vec4::new(1.0, 2.0, 3.0, 4.0)); - } - - #[test] - fn test_mat4_round_trip() { - test_round_trip(Mat4::IDENTITY); - } - - #[test] - fn test_array_round_trip() { - test_round_trip([-10i32; 1024]); - test_round_trip([Vec2::ZERO, Vec2::ONE, Vec2::Y, Vec2::X]); - } -} diff --git a/crates/bevy_core/src/float_ord.rs b/crates/bevy_core/src/float_ord.rs index 798e0d9e3a..cd573ca5fc 100644 --- a/crates/bevy_core/src/float_ord.rs +++ b/crates/bevy_core/src/float_ord.rs @@ -1,4 +1,3 @@ -use crate::bytes_of; use std::{ cmp::Ordering, hash::{Hash, Hasher}, @@ -42,12 +41,12 @@ impl Hash for FloatOrd { fn hash(&self, state: &mut H) { if self.0.is_nan() { // Ensure all NaN representations hash to the same value - state.write(bytes_of(&f32::NAN)) + state.write(bytemuck::bytes_of(&f32::NAN)) } else if self.0 == 0.0 { // Ensure both zeroes hash to the same value - state.write(bytes_of(&0.0f32)) + state.write(bytemuck::bytes_of(&0.0f32)) } else { - state.write(bytes_of(&self.0)); + state.write(bytemuck::bytes_of(&self.0)); } } } diff --git a/crates/bevy_core/src/label.rs b/crates/bevy_core/src/label.rs deleted file mode 100644 index 4b805641ef..0000000000 --- a/crates/bevy_core/src/label.rs +++ /dev/null @@ -1,256 +0,0 @@ -use bevy_ecs::{ - component::Component, - entity::Entity, - query::Changed, - reflect::ReflectComponent, - system::{Query, RemovedComponents, ResMut}, -}; -use bevy_reflect::Reflect; -use bevy_utils::{HashMap, HashSet}; -use std::{ - borrow::Cow, - fmt::Debug, - ops::{Deref, DerefMut}, -}; - -/// A collection of labels -#[derive(Component, Default, Reflect)] -#[reflect(Component)] -pub struct Labels { - labels: HashSet>, -} - -impl Debug for Labels { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let mut list = f.debug_list(); - for label in self.iter() { - list.entry(&label); - } - - list.finish() - } -} - -impl<'a, T, L: Into>> From for Labels -where - T: IntoIterator, -{ - fn from(value: T) -> Self { - let mut labels = HashSet::default(); - for label in value { - labels.insert(label.into()); - } - Self { labels } - } -} - -impl Labels { - pub fn contains>>(&self, label: T) -> bool { - self.labels.contains(&label.into()) - } - - pub fn insert>>(&mut self, label: T) { - self.labels.insert(label.into()); - } - - pub fn remove>>(&mut self, label: T) { - self.labels.remove(&label.into()); - } - - pub fn iter(&self) -> impl Iterator { - self.labels.iter().map(|label| label.deref()) - } -} - -/// Maintains a mapping from [Entity](bevy_ecs::prelude::Entity) ids to entity labels and entity -/// labels to [Entities](bevy_ecs::prelude::Entity). -#[derive(Debug, Default)] -pub struct EntityLabels { - label_entities: HashMap, Vec>, - entity_labels: HashMap>>, -} - -impl EntityLabels { - pub fn get(&self, label: &str) -> &[Entity] { - self.label_entities - .get(label) - .map(|entities| entities.as_slice()) - .unwrap_or(&[]) - } -} - -pub(crate) fn entity_labels_system( - mut entity_labels: ResMut, - removed_labels: RemovedComponents, - query: Query<(Entity, &Labels), Changed>, -) { - let entity_labels = entity_labels.deref_mut(); - - for entity in removed_labels.iter() { - if let Some(labels) = entity_labels.entity_labels.get(&entity) { - for label in labels.iter() { - if let Some(entities) = entity_labels.label_entities.get_mut(label) { - entities.retain(|e| *e != entity); - } - } - } - } - - for (entity, labels) in query.iter() { - let current_labels = entity_labels - .entity_labels - .entry(entity) - .or_insert_with(HashSet::default); - - for removed_label in current_labels.difference(&labels.labels) { - if let Some(entities) = entity_labels.label_entities.get_mut(removed_label) { - entities.retain(|e| *e != entity); - } - } - - for added_label in labels.labels.difference(current_labels) { - entity_labels - .label_entities - .entry(added_label.clone()) - .or_insert_with(Vec::new) - .push(entity); - } - - *current_labels = labels.labels.clone(); - } -} - -#[cfg(test)] -mod tests { - use bevy_ecs::{ - schedule::{Schedule, Stage, SystemStage}, - world::World, - }; - - use super::*; - - fn setup() -> (World, Schedule) { - let mut world = World::new(); - world.insert_resource(EntityLabels::default()); - let mut schedule = Schedule::default(); - schedule.add_stage("test", SystemStage::single_threaded()); - schedule.add_system_to_stage("test", entity_labels_system); - (world, schedule) - } - - fn holy_cow() -> Labels { - Labels::from(["holy", "cow"].iter().cloned()) - } - - fn holy_shamoni() -> Labels { - Labels::from(["holy", "shamoni"].iter().cloned()) - } - - #[test] - fn adds_spawned_entity() { - let (mut world, mut schedule) = setup(); - - let e1 = world.spawn().insert(holy_cow()).id(); - schedule.run(&mut world); - - let entity_labels = world.get_resource::().unwrap(); - assert_eq!(entity_labels.get("holy"), &[e1], "holy"); - assert_eq!(entity_labels.get("cow"), &[e1], "cow"); - assert_eq!(entity_labels.get("shalau"), &[], "shalau"); - } - - #[test] - fn add_labels() { - let (mut world, mut schedule) = setup(); - let e1 = world.spawn().insert(holy_cow()).id(); - schedule.run(&mut world); - - world.get_mut::(e1).unwrap().insert("shalau"); - schedule.run(&mut world); - - let entity_labels = world.get_resource::().unwrap(); - assert_eq!(entity_labels.get("holy"), &[e1], "holy"); - assert_eq!(entity_labels.get("cow"), &[e1], "cow"); - assert_eq!(entity_labels.get("shalau"), &[e1], "shalau"); - } - - #[test] - fn remove_labels() { - let (mut world, mut schedule) = setup(); - let e1 = world.spawn().insert(holy_cow()).id(); - schedule.run(&mut world); - - world.get_mut::(e1).unwrap().remove("holy"); - schedule.run(&mut world); - - let entity_labels = world.get_resource::().unwrap(); - assert_eq!(entity_labels.get("holy"), &[], "holy"); - assert_eq!(entity_labels.get("cow"), &[e1], "cow"); - assert_eq!(entity_labels.get("shalau"), &[], "shalau"); - } - - #[test] - fn removes_despawned_entity() { - let (mut world, mut schedule) = setup(); - let e1 = world.spawn().insert(holy_cow()).id(); - schedule.run(&mut world); - - assert!(world.despawn(e1)); - schedule.run(&mut world); - - let entity_labels = world.get_resource::().unwrap(); - assert_eq!(entity_labels.get("holy"), &[], "holy"); - assert_eq!(entity_labels.get("cow"), &[], "cow"); - assert_eq!(entity_labels.get("shalau"), &[], "shalau"); - } - - #[test] - fn removes_labels_when_component_removed() { - let (mut world, mut schedule) = setup(); - let e1 = world.spawn().insert(holy_cow()).id(); - schedule.run(&mut world); - - world.entity_mut(e1).remove::().unwrap(); - schedule.run(&mut world); - - let entity_labels = world.get_resource::().unwrap(); - assert_eq!(entity_labels.get("holy"), &[], "holy"); - assert_eq!(entity_labels.get("cow"), &[], "cow"); - assert_eq!(entity_labels.get("shalau"), &[], "shalau"); - } - - #[test] - fn adds_another_spawned_entity() { - let (mut world, mut schedule) = setup(); - let e1 = world.spawn().insert(holy_cow()).id(); - schedule.run(&mut world); - - let e2 = world.spawn().insert(holy_shamoni()).id(); - schedule.run(&mut world); - - let entity_labels = world.get_resource::().unwrap(); - assert_eq!(entity_labels.get("holy"), &[e1, e2], "holy"); - assert_eq!(entity_labels.get("cow"), &[e1], "cow"); - assert_eq!(entity_labels.get("shamoni"), &[e2], "shamoni"); - assert_eq!(entity_labels.get("shalau"), &[], "shalau"); - } - - #[test] - fn removes_despawned_entity_but_leaves_other() { - let (mut world, mut schedule) = setup(); - let e1 = world.spawn().insert(holy_cow()).id(); - schedule.run(&mut world); - - let e2 = world.spawn().insert(holy_shamoni()).id(); - schedule.run(&mut world); - - assert!(world.despawn(e1)); - schedule.run(&mut world); - - let entity_labels = world.get_resource::().unwrap(); - assert_eq!(entity_labels.get("holy"), &[e2], "holy"); - assert_eq!(entity_labels.get("cow"), &[], "cow"); - assert_eq!(entity_labels.get("shamoni"), &[e2], "shamoni"); - assert_eq!(entity_labels.get("shalau"), &[], "shalau"); - } -} diff --git a/crates/bevy_core/src/lib.rs b/crates/bevy_core/src/lib.rs index 2e8066d62f..f943b28142 100644 --- a/crates/bevy_core/src/lib.rs +++ b/crates/bevy_core/src/lib.rs @@ -1,20 +1,21 @@ -mod bytes; +#![warn(missing_docs)] +//! This crate provides core functionality for Bevy Engine. + mod float_ord; -mod label; mod name; mod task_pool_options; mod time; -pub use bytes::*; +pub use bytemuck::{bytes_of, cast_slice, Pod, Zeroable}; pub use float_ord::*; -pub use label::*; pub use name::*; pub use task_pool_options::DefaultTaskPoolOptions; pub use time::*; pub mod prelude { + //! The Bevy Core Prelude. #[doc(hidden)] - pub use crate::{DefaultTaskPoolOptions, EntityLabels, Labels, Name, Time, Timer}; + pub use crate::{DefaultTaskPoolOptions, Name, Time, Timer}; } use bevy_app::prelude::*; @@ -30,6 +31,7 @@ use std::ops::Range; #[derive(Default)] pub struct CorePlugin; +/// A `SystemLabel` enum for ordering systems relative to core Bevy systems. #[derive(Debug, PartialEq, Eq, Clone, Hash, SystemLabel)] pub enum CoreSystem { /// Updates the elapsed time. Any system that interacts with [Time] component should run after @@ -47,13 +49,11 @@ impl Plugin for CorePlugin { .create_default_pools(&mut app.world); app.init_resource::