Rework manual event iterator so we can actually name the type (#5735)
# Objective - Be able to name the type that `ManualEventReader::iter/iter_with_id` returns and `EventReader::iter/iter_with_id` by proxy. Currently for the purpose of https://github.com/bevyengine/bevy/pull/5719 ## Solution - Create a custom `Iterator` type.
This commit is contained in:
parent
965ebeff59
commit
9717204aef
@ -4,8 +4,7 @@ use crate as bevy_ecs;
|
|||||||
use crate::system::{Local, Res, ResMut, Resource, SystemParam};
|
use crate::system::{Local, Res, ResMut, Resource, SystemParam};
|
||||||
use bevy_utils::tracing::trace;
|
use bevy_utils::tracing::trace;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::{fmt, hash::Hash, marker::PhantomData};
|
use std::{fmt, hash::Hash, iter::Chain, marker::PhantomData, slice::Iter};
|
||||||
|
|
||||||
/// A type that can be stored in an [`Events<E>`] resource
|
/// A type that can be stored in an [`Events<E>`] resource
|
||||||
/// You can conveniently access events using the [`EventReader`] and [`EventWriter`] system parameter.
|
/// You can conveniently access events using the [`EventReader`] and [`EventWriter`] system parameter.
|
||||||
///
|
///
|
||||||
@ -194,18 +193,13 @@ impl<'w, 's, E: Event> EventReader<'w, 's, E> {
|
|||||||
/// Iterates over the events this [`EventReader`] has not seen yet. This updates the
|
/// Iterates over the events this [`EventReader`] has not seen yet. This updates the
|
||||||
/// [`EventReader`]'s event counter, which means subsequent event reads will not include events
|
/// [`EventReader`]'s event counter, which means subsequent event reads will not include events
|
||||||
/// that happened before now.
|
/// that happened before now.
|
||||||
pub fn iter(&mut self) -> impl DoubleEndedIterator<Item = &E> + ExactSizeIterator<Item = &E> {
|
pub fn iter(&mut self) -> ManualEventIterator<'_, E> {
|
||||||
self.iter_with_id().map(|(event, _id)| event)
|
self.reader.iter(&self.events)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Like [`iter`](Self::iter), except also returning the [`EventId`] of the events.
|
/// Like [`iter`](Self::iter), except also returning the [`EventId`] of the events.
|
||||||
pub fn iter_with_id(
|
pub fn iter_with_id(&mut self) -> ManualEventIteratorWithId<'_, E> {
|
||||||
&mut self,
|
self.reader.iter_with_id(&self.events)
|
||||||
) -> impl DoubleEndedIterator<Item = (&E, EventId<E>)> + ExactSizeIterator<Item = (&E, EventId<E>)>
|
|
||||||
{
|
|
||||||
self.reader.iter_with_id(&self.events).inspect(|(_, id)| {
|
|
||||||
trace!("EventReader::iter() -> {}", id);
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determines the number of events available to be read from this [`EventReader`] without consuming any.
|
/// Determines the number of events available to be read from this [`EventReader`] without consuming any.
|
||||||
@ -337,34 +331,16 @@ impl<E: Event> Default for ManualEventReader<E> {
|
|||||||
#[allow(clippy::len_without_is_empty)] // Check fails since the is_empty implementation has a signature other than `(&self) -> bool`
|
#[allow(clippy::len_without_is_empty)] // Check fails since the is_empty implementation has a signature other than `(&self) -> bool`
|
||||||
impl<E: Event> ManualEventReader<E> {
|
impl<E: Event> ManualEventReader<E> {
|
||||||
/// See [`EventReader::iter`]
|
/// See [`EventReader::iter`]
|
||||||
pub fn iter<'a>(
|
pub fn iter<'a>(&'a mut self, events: &'a Events<E>) -> ManualEventIterator<'a, E> {
|
||||||
&'a mut self,
|
self.iter_with_id(events).without_id()
|
||||||
events: &'a Events<E>,
|
|
||||||
) -> impl DoubleEndedIterator<Item = &'a E> + ExactSizeIterator<Item = &'a E> {
|
|
||||||
self.iter_with_id(events).map(|(e, _)| e)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See [`EventReader::iter_with_id`]
|
/// See [`EventReader::iter_with_id`]
|
||||||
pub fn iter_with_id<'a>(
|
pub fn iter_with_id<'a>(
|
||||||
&'a mut self,
|
&'a mut self,
|
||||||
events: &'a Events<E>,
|
events: &'a Events<E>,
|
||||||
) -> impl DoubleEndedIterator<Item = (&'a E, EventId<E>)>
|
) -> ManualEventIteratorWithId<'a, E> {
|
||||||
+ ExactSizeIterator<Item = (&'a E, EventId<E>)> {
|
ManualEventIteratorWithId::new(self, events)
|
||||||
let a_index = (self.last_event_count).saturating_sub(events.events_a.start_event_count);
|
|
||||||
let b_index = (self.last_event_count).saturating_sub(events.events_b.start_event_count);
|
|
||||||
let a = events.events_a.get(a_index..).unwrap_or_default();
|
|
||||||
let b = events.events_b.get(b_index..).unwrap_or_default();
|
|
||||||
|
|
||||||
let unread_count = a.len() + b.len();
|
|
||||||
// Ensure `len` is implemented correctly
|
|
||||||
debug_assert_eq!(unread_count, self.len(events));
|
|
||||||
self.last_event_count = events.event_count - unread_count;
|
|
||||||
// Iterate the oldest first, then the newer events
|
|
||||||
let iterator = a.iter().chain(b.iter());
|
|
||||||
iterator
|
|
||||||
.map(|e| (&e.event, e.event_id))
|
|
||||||
.with_exact_size(unread_count)
|
|
||||||
.inspect(move |(_, id)| self.last_event_count = (id.id + 1).max(self.last_event_count))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See [`EventReader::len`]
|
/// See [`EventReader::len`]
|
||||||
@ -392,57 +368,114 @@ impl<E: Event> ManualEventReader<E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait IteratorExt {
|
pub struct ManualEventIterator<'a, E: Event> {
|
||||||
fn with_exact_size(self, len: usize) -> ExactSize<Self>
|
iter: ManualEventIteratorWithId<'a, E>,
|
||||||
where
|
|
||||||
Self: Sized,
|
|
||||||
{
|
|
||||||
ExactSize::new(self, len)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<I> IteratorExt for I where I: Iterator {}
|
|
||||||
|
|
||||||
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct ExactSize<I> {
|
|
||||||
iter: I,
|
|
||||||
len: usize,
|
|
||||||
}
|
|
||||||
impl<I> ExactSize<I> {
|
|
||||||
fn new(iter: I, len: usize) -> Self {
|
|
||||||
ExactSize { iter, len }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: Iterator> Iterator for ExactSize<I> {
|
impl<'a, E: Event> Iterator for ManualEventIterator<'a, E> {
|
||||||
type Item = I::Item;
|
type Item = &'a E;
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
#[inline]
|
self.iter.next().map(|(event, _)| event)
|
||||||
fn next(&mut self) -> Option<I::Item> {
|
|
||||||
self.iter.next().map(|e| {
|
|
||||||
self.len -= 1;
|
|
||||||
e
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
(self.len, Some(self.len))
|
self.iter.size_hint()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: DoubleEndedIterator> DoubleEndedIterator for ExactSize<I> {
|
impl<'a, E: Event> ExactSizeIterator for ManualEventIterator<'a, E> {
|
||||||
#[inline]
|
fn len(&self) -> usize {
|
||||||
fn next_back(&mut self) -> Option<I::Item> {
|
self.iter.len()
|
||||||
self.iter.next_back().map(|e| {
|
|
||||||
self.len -= 1;
|
|
||||||
e
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<I: Iterator> ExactSizeIterator for ExactSize<I> {
|
|
||||||
|
impl<'a, E: Event> DoubleEndedIterator for ManualEventIterator<'a, E> {
|
||||||
|
fn next_back(&mut self) -> Option<Self::Item> {
|
||||||
|
self.iter.next_back().map(|(event, _)| event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ManualEventIteratorWithId<'a, E: Event> {
|
||||||
|
reader: &'a mut ManualEventReader<E>,
|
||||||
|
chain: Chain<Iter<'a, EventInstance<E>>, Iter<'a, EventInstance<E>>>,
|
||||||
|
unread: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn event_trace<E: Event>(id: EventId<E>) {
|
||||||
|
trace!("EventReader::iter() -> {}", id);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, E: Event> ManualEventIteratorWithId<'a, E> {
|
||||||
|
pub fn new(reader: &'a mut ManualEventReader<E>, events: &'a Events<E>) -> Self {
|
||||||
|
let a_index = (reader.last_event_count).saturating_sub(events.events_a.start_event_count);
|
||||||
|
let b_index = (reader.last_event_count).saturating_sub(events.events_b.start_event_count);
|
||||||
|
let a = events.events_a.get(a_index..).unwrap_or_default();
|
||||||
|
let b = events.events_b.get(b_index..).unwrap_or_default();
|
||||||
|
|
||||||
|
let unread_count = a.len() + b.len();
|
||||||
|
// Ensure `len` is implemented correctly
|
||||||
|
debug_assert_eq!(unread_count, reader.len(events));
|
||||||
|
reader.last_event_count = events.event_count - unread_count;
|
||||||
|
// Iterate the oldest first, then the newer events
|
||||||
|
let chain = a.iter().chain(b.iter());
|
||||||
|
|
||||||
|
Self {
|
||||||
|
reader,
|
||||||
|
chain,
|
||||||
|
unread: unread_count,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Iterate over only the events.
|
||||||
|
pub fn without_id(self) -> ManualEventIterator<'a, E> {
|
||||||
|
ManualEventIterator { iter: self }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, E: Event> Iterator for ManualEventIteratorWithId<'a, E> {
|
||||||
|
type Item = (&'a E, EventId<E>);
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
match self
|
||||||
|
.chain
|
||||||
|
.next()
|
||||||
|
.map(|instance| (&instance.event, instance.event_id))
|
||||||
|
{
|
||||||
|
Some(item) => {
|
||||||
|
event_trace(item.1);
|
||||||
|
self.reader.last_event_count += 1;
|
||||||
|
self.unread -= 1;
|
||||||
|
Some(item)
|
||||||
|
}
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
self.chain.size_hint()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, E: Event> DoubleEndedIterator for ManualEventIteratorWithId<'a, E> {
|
||||||
|
fn next_back(&mut self) -> Option<Self::Item> {
|
||||||
|
match self
|
||||||
|
.chain
|
||||||
|
.next_back()
|
||||||
|
.map(|instance| (&instance.event, instance.event_id))
|
||||||
|
{
|
||||||
|
Some(item) => {
|
||||||
|
event_trace(item.1);
|
||||||
|
self.unread -= 1;
|
||||||
|
Some(item)
|
||||||
|
}
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, E: Event> ExactSizeIterator for ManualEventIteratorWithId<'a, E> {
|
||||||
fn len(&self) -> usize {
|
fn len(&self) -> usize {
|
||||||
self.len
|
self.unread
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -548,6 +581,34 @@ impl<E: Event> Events<E> {
|
|||||||
) -> impl DoubleEndedIterator<Item = &E> + ExactSizeIterator<Item = &E> {
|
) -> impl DoubleEndedIterator<Item = &E> + ExactSizeIterator<Item = &E> {
|
||||||
self.events_b.iter().map(|i| &i.event)
|
self.events_b.iter().map(|i| &i.event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a specific event by id if it still exists in the events buffer.
|
||||||
|
pub fn get_event(&self, id: usize) -> Option<(&E, EventId<E>)> {
|
||||||
|
if id < self.oldest_id() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let sequence = self.sequence(id);
|
||||||
|
let index = id.saturating_sub(sequence.start_event_count);
|
||||||
|
|
||||||
|
sequence
|
||||||
|
.get(index)
|
||||||
|
.map(|instance| (&instance.event, instance.event_id))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Oldest id still in the events buffer.
|
||||||
|
pub fn oldest_id(&self) -> usize {
|
||||||
|
self.events_a.start_event_count
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Which event buffer is this event id a part of.
|
||||||
|
fn sequence(&self, id: usize) -> &EventSequence<E> {
|
||||||
|
if id < self.events_b.start_event_count {
|
||||||
|
&self.events_a
|
||||||
|
} else {
|
||||||
|
&self.events_b
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: Event> std::iter::Extend<E> for Events<E> {
|
impl<E: Event> std::iter::Extend<E> for Events<E> {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user