Skip to content

Commit

Permalink
Fix bug in event broadcasting
Browse files Browse the repository at this point in the history
When a component is added or removed from an entity, the system list
currently being iterated over may no longer match the target entity.
To fix this, events are now only handled once the current event has
finished broadcasting. Still not entirely sure that this is the most
desirable behavior though.

The `EventPtr` and `EventMut` interface also had an update.
  • Loading branch information
rj00a committed Feb 12, 2024
1 parent f74327f commit 7846ef3
Show file tree
Hide file tree
Showing 7 changed files with 336 additions and 328 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Change Log

## Unreleased

- Fixed a bug in event propagation.
- The behavior of the event queue has changed. The next event in the queue is handled only once the current event has finished broadcasting.
- Changed `EventPtr` interface and relaxed `Send` and `Sync` bounds for `EventMut`.

## 0.2.2 - 2024-02-8

- Update documentation
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ It aims to have a small but maximally expressive set of features that are easy a

## Features

- In addition to the usual Entities, Components, and Systems, `evenio` introduces _events_ as a first-class citizen.
Rather than restricting systems to run once every frame/update in a fixed order, systems are generalized as _event handlers_.
- In addition to the usual Entities, Components, and Systems, `evenio` introduces events as a first-class citizen.
Rather than restricting systems to run once every frame/update in a fixed order, systems are generalized as event handlers.
The control flow of the entire program is then defined by the flow of events between systems.
- Structural changes to the world (such as entity despawning, component additions/removals, etc.) are mediated by events, allowing systems to hook into their occurrence.
- _Targeted events_ enable systems to efficiently filter events based on queries.
- Targeted events enable systems to efficiently filter events based on queries.
- Component types, event types, and systems are identified with generational indices, allowing them to be added and removed dynamically.
- Execute systems in parallel with [Rayon].
- Core of the library does not depend on Rust's type system.
Expand Down
37 changes: 12 additions & 25 deletions src/assert.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Utilities for runtime and compile-time assertions.

use alloc::vec::Vec;
use core::marker::PhantomData;
use core::slice::SliceIndex;
use core::{fmt, mem};

use slab::Slab;
Expand All @@ -16,7 +16,7 @@ const _: () = assert!(

/// Extension trait for checked array indexing with checks removed in release
/// mode.
pub(crate) trait GetDebugChecked {
pub(crate) trait GetDebugChecked<Idx> {
type Output: ?Sized;

/// Gets a reference to the element at the given index.
Expand All @@ -28,7 +28,7 @@ pub(crate) trait GetDebugChecked {
///
/// - `idx` must be in bounds.
#[track_caller]
unsafe fn get_debug_checked(&self, idx: usize) -> &Self::Output;
unsafe fn get_debug_checked(&self, idx: Idx) -> &Self::Output;
/// Gets a mutable reference to the element at the given index.
///
/// If `idx` is not in bounds, a panic occurs in debug mode and Undefined
Expand All @@ -38,23 +38,24 @@ pub(crate) trait GetDebugChecked {
///
/// - `idx` must be in bounds.
#[track_caller]
unsafe fn get_debug_checked_mut(&mut self, idx: usize) -> &mut Self::Output;
unsafe fn get_debug_checked_mut(&mut self, idx: Idx) -> &mut Self::Output;
}

impl<T> GetDebugChecked for [T] {
type Output = T;
impl<T, I> GetDebugChecked<I> for [T]
where
I: SliceIndex<[T]>,
{
type Output = I::Output;

#[inline]
unsafe fn get_debug_checked(&self, idx: usize) -> &Self::Output {
unsafe fn get_debug_checked(&self, idx: I) -> &Self::Output {
#[cfg(debug_assertions)]
return &self[idx];

#[cfg(not(debug_assertions))]
return self.get_unchecked(idx);
}

#[inline]
unsafe fn get_debug_checked_mut(&mut self, idx: usize) -> &mut Self::Output {
unsafe fn get_debug_checked_mut(&mut self, idx: I) -> &mut Self::Output {
#[cfg(debug_assertions)]
return &mut self[idx];

Expand All @@ -63,22 +64,8 @@ impl<T> GetDebugChecked for [T] {
}
}

impl<T> GetDebugChecked for Vec<T> {
type Output = T;

#[inline]
unsafe fn get_debug_checked(&self, idx: usize) -> &Self::Output {
self.as_slice().get_debug_checked(idx)
}

#[inline]
unsafe fn get_debug_checked_mut(&mut self, idx: usize) -> &mut Self::Output {
self.as_mut_slice().get_debug_checked_mut(idx)
}
}

// Don't use `Slab::get_unchecked` because there's a panicking branch. https://github.com/tokio-rs/slab/pull/74
impl<T> GetDebugChecked for Slab<T> {
impl<T> GetDebugChecked<usize> for Slab<T> {
type Output = T;

#[inline]
Expand Down
3 changes: 0 additions & 3 deletions src/blob_vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,6 @@ impl BlobVec {
/// - `drop` must be safe to call with elements of this `BlobVec` as
/// described by [`DropFn`]'s documentation.
pub(crate) unsafe fn new(layout: Layout, drop: DropFn) -> Self {
// // SAFETY: `Layout` guarantees alignment is non-zero.
// let data = NonNull::new(layout.align() as *mut u8).unwrap_debug_checked();

Self {
elem_layout: pad_to_align(&layout),
len: 0,
Expand Down
Loading

0 comments on commit 7846ef3

Please sign in to comment.