Skip to content

Commit 283b1ad

Browse files
author
Jonathan Woollett-Light
committed
feat: Lazy iterator
`wait` now returns an iterator that allows lazily evaluating event closures. This allows for returning an error when the 1st closure returns an error, rather than always needing to evaluate every closure. Signed-off-by: Jonathan Woollett-Light <[email protected]>
1 parent 9d9636c commit 283b1ad

File tree

2 files changed

+128
-52
lines changed

2 files changed

+128
-52
lines changed

benches/main.rs

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,14 @@ fn run_basic_subscriber(c: &mut Criterion) {
4747
event_fd
4848
}).collect::<Vec<_>>();
4949

50-
let expected = vec![();usize::try_from(no_of_subscribers).unwrap()];
50+
let n = usize::try_from(no_of_subscribers).unwrap();
5151
c.bench_function("process_basic", |b| {
5252
b.iter(|| {
53-
assert_eq!(event_manager.wait(Some(0)), Ok(expected.as_slice()));
53+
let mut iter = event_manager.wait(Some(0)).unwrap();
54+
for _ in 0..n {
55+
assert_eq!(iter.next(), Some(&mut ()));
56+
}
57+
assert_eq!(iter.next(), None);
5458
})
5559
});
5660

@@ -96,10 +100,14 @@ fn run_arc_mutex_subscriber(c: &mut Criterion) {
96100
(event_fd,counter)
97101
}).collect::<Vec<_>>();
98102

99-
let expected = vec![();usize::try_from(no_of_subscribers).unwrap()];
103+
let n = usize::try_from(no_of_subscribers).unwrap();
100104
c.bench_function("process_with_arc_mutex", |b| {
101105
b.iter(|| {
102-
assert_eq!(event_manager.wait(Some(0)), Ok(expected.as_slice()));
106+
let mut iter = event_manager.wait(Some(0)).unwrap();
107+
for _ in 0..n {
108+
assert_eq!(iter.next(), Some(&mut ()));
109+
}
110+
assert_eq!(iter.next(), None);
103111
})
104112
});
105113

@@ -146,10 +154,14 @@ fn run_subscriber_with_inner_mut(c: &mut Criterion) {
146154
(event_fd,counter)
147155
}).collect::<Vec<_>>();
148156

149-
let expected = vec![();usize::try_from(no_of_subscribers).unwrap()];
157+
let n = usize::try_from(no_of_subscribers).unwrap();
150158
c.bench_function("process_with_inner_mut", |b| {
151159
b.iter(|| {
152-
assert_eq!(event_manager.wait(Some(0)), Ok(expected.as_slice()));
160+
let mut iter = event_manager.wait(Some(0)).unwrap();
161+
for _ in 0..n {
162+
assert_eq!(iter.next(), Some(&mut ()));
163+
}
164+
assert_eq!(iter.next(), None);
153165
})
154166
});
155167

@@ -225,8 +237,8 @@ fn run_multiple_subscriber_types(c: &mut Criterion) {
225237
.add(
226238
inner_subscribers[i].as_fd(),
227239
EventSet::IN | EventSet::ERROR | EventSet::HANG_UP,
228-
Box::new(
229-
move |_: &mut EventManager<()>, event_set: EventSet| match event_set {
240+
Box::new(move |_: &mut EventManager<()>, event_set: EventSet| {
241+
match event_set {
230242
EventSet::IN => {
231243
data_clone[i].fetch_add(1, Ordering::SeqCst);
232244
}
@@ -237,8 +249,8 @@ fn run_multiple_subscriber_types(c: &mut Criterion) {
237249
panic!("Cannot continue execution. Associated fd was closed.");
238250
}
239251
_ => {}
240-
},
241-
),
252+
}
253+
}),
242254
)
243255
.unwrap();
244256
}
@@ -247,10 +259,14 @@ fn run_multiple_subscriber_types(c: &mut Criterion) {
247259
})
248260
.collect::<Vec<_>>();
249261

250-
let expected = vec![();usize::try_from(total).unwrap()];
262+
let n = usize::try_from(total).unwrap();
251263
c.bench_function("process_dynamic_dispatch", |b| {
252264
b.iter(|| {
253-
assert_eq!(event_manager.wait(Some(0)), Ok(expected.as_slice()));
265+
let mut iter = event_manager.wait(Some(0)).unwrap();
266+
for _ in 0..n {
267+
assert_eq!(iter.next(), Some(&mut ()));
268+
}
269+
assert_eq!(iter.next(), None);
254270
})
255271
});
256272

@@ -294,10 +310,14 @@ fn run_with_few_active_events(c: &mut Criterion) {
294310
event_fd
295311
}).collect::<Vec<_>>();
296312

297-
let expected = vec![();usize::try_from(active).unwrap()];
313+
let n = usize::try_from(active).unwrap();
298314
c.bench_function("process_dispatch_few_events", |b| {
299315
b.iter(|| {
300-
assert_eq!(event_manager.wait(Some(0)), Ok(expected.as_slice()));
316+
let mut iter = event_manager.wait(Some(0)).unwrap();
317+
for _ in 0..n {
318+
assert_eq!(iter.next(), Some(&mut ()));
319+
}
320+
assert_eq!(iter.next(), None);
301321
})
302322
});
303323

src/lib.rs

Lines changed: 94 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -58,21 +58,15 @@ impl<T> BufferedEventManager<T> {
5858
///
5959
/// When the value given in timeout does not fit within an `i32` e.g.
6060
/// `timeout.map(|u| i32::try_from(u).unwrap())`.
61-
pub fn wait(&mut self, timeout: Option<u32>) -> Result<&[T], i32> {
61+
pub fn wait(&mut self, timeout: Option<u32>) -> Result<Iter<'_, T>, i32> {
6262
// SAFETY: `EventManager::wait` initializes N element from the start of the slice and only
6363
// accesses these, thus it will never access uninitialized memory, making this safe.
6464
unsafe {
6565
self.buffer.set_len(self.buffer.capacity());
6666
self.output_buffer.set_len(self.output_buffer.capacity());
6767
}
68-
let n = self
69-
.event_manager
70-
.wait(timeout, &mut self.buffer, &mut self.output_buffer)?;
71-
unsafe {
72-
Ok(self
73-
.output_buffer
74-
.get_unchecked(..usize::try_from(n).unwrap_unchecked()))
75-
}
68+
self.event_manager
69+
.wait(timeout, &mut self.buffer, &mut self.output_buffer)
7670
}
7771

7872
/// Creates new event manager.
@@ -123,6 +117,62 @@ impl<T> std::fmt::Debug for EventManager<T> {
123117
}
124118
}
125119

120+
#[derive(Debug)]
121+
pub struct Iter<'a, T> {
122+
event_manager: &'a mut EventManager<T>,
123+
buffer: &'a [libc::epoll_event],
124+
output_buffer: &'a mut [T],
125+
index: usize,
126+
}
127+
impl<'a, T> Iter<'a, T> {
128+
/// Returns a mutable slice of all the items previously returned by [`Iter::next`].
129+
pub fn as_mut_slice(&'a mut self) -> &'a mut [T] {
130+
&mut self.output_buffer[..self.index]
131+
}
132+
/// Returns a slice of all the items previously returned by [`Iter::next`].
133+
pub fn as_slice(&'a self) -> &'a [T] {
134+
&self.output_buffer[..self.index]
135+
}
136+
}
137+
impl<'a, T> Iterator for Iter<'a, T> {
138+
type Item = &'a mut T;
139+
fn next(&mut self) -> Option<Self::Item> {
140+
debug_assert_eq!(self.buffer.len(), self.output_buffer.len());
141+
142+
if self.index >= self.buffer.len() {
143+
return None;
144+
}
145+
unsafe {
146+
let event = self.buffer.get_unchecked(self.index);
147+
// For all events which can fire there exists an entry within `self.events` thus
148+
// it is safe to unwrap here.
149+
let f: *const dyn Fn(&mut EventManager<T>, EventSet) -> T = self
150+
.event_manager
151+
.events
152+
.get(&i32::try_from(event.u64).unwrap_unchecked())
153+
.unwrap_unchecked();
154+
self.output_buffer[self.index] = (*f)(
155+
self.event_manager,
156+
EventSet::from_bits_unchecked(event.events),
157+
);
158+
159+
// SAFETY: This is always safe. This is required as the current standard library trait
160+
// doesn't support lending iteraor semantics.
161+
let temp = Some(std::mem::transmute(&mut self.output_buffer[self.index]));
162+
163+
self.index += 1;
164+
165+
temp
166+
}
167+
}
168+
169+
/// O(1)
170+
fn size_hint(&self) -> (usize, Option<usize>) {
171+
let n = self.buffer.len() - self.index;
172+
(n, Some(n))
173+
}
174+
}
175+
126176
impl<T> EventManager<T> {
127177
/// Add an entry to the interest list of the epoll file descriptor.
128178
///
@@ -186,12 +236,12 @@ impl<T> EventManager<T> {
186236
///
187237
/// When the value given in timeout does not fit within an `i32` e.g.
188238
/// `timeout.map(|u| i32::try_from(u).unwrap())`.
189-
pub fn wait(
190-
&mut self,
239+
pub fn wait<'a>(
240+
&'a mut self,
191241
timeout: Option<u32>,
192-
buffer: &mut [libc::epoll_event],
193-
output_buffer: &mut [T],
194-
) -> Result<i32, i32> {
242+
buffer: &'a mut [libc::epoll_event],
243+
output_buffer: &'a mut [T],
244+
) -> Result<Iter<'a, T>, i32> {
195245
// SAFETY: Always safe.
196246
match unsafe {
197247
libc::epoll_wait(
@@ -204,18 +254,13 @@ impl<T> EventManager<T> {
204254
-1 => Err(errno()),
205255
// SAFETY: `x` elements are initialized by `libc::epoll_wait`.
206256
n @ 0.. => unsafe {
207-
#[allow(clippy::needless_range_loop)]
208-
for i in 0..usize::try_from(n).unwrap_unchecked() {
209-
let event = buffer[i];
210-
// For all events which can fire there exists an entry within `self.events` thus
211-
// it is safe to unwrap here.
212-
let f: *const dyn Fn(&mut EventManager<T>, EventSet) -> T = self
213-
.events
214-
.get(&i32::try_from(event.u64).unwrap_unchecked())
215-
.unwrap_unchecked();
216-
output_buffer[i] = (*f)(self, EventSet::from_bits_unchecked(event.events));
217-
}
218-
Ok(n)
257+
let n = usize::try_from(n).unwrap_unchecked();
258+
Ok(Iter {
259+
event_manager: self,
260+
buffer: &mut buffer[..n],
261+
output_buffer: &mut output_buffer[..n],
262+
index: 0,
263+
})
219264
},
220265
_ => unreachable!(),
221266
}
@@ -286,17 +331,19 @@ mod tests {
286331

287332
// The file descriptor has been pre-armed, this will immediately call the respective
288333
// closure.
289-
let vec = vec![()];
290-
assert_eq!(manager.wait(Some(10)), Ok(vec.as_slice()));
334+
let mut iter = manager.wait(Some(10)).unwrap();
335+
assert_eq!(iter.next(), Some(&mut ()));
336+
assert_eq!(iter.next(), None);
291337

292338
// As the closure will flip the atomic boolean we assert it has flipped correctly.
293339
assert!(COUNT.load(Ordering::SeqCst));
294340

295341
// At this point we have called the closure, since the closure removes the event fd from the
296342
// interest list of the inner epoll, calling this again should timeout as there are no event
297343
// fd in the inner epolls interest list which could trigger.
298-
let vec = vec![];
299-
assert_eq!(manager.wait(Some(10)), Ok(vec.as_slice()));
344+
let mut iter = manager.wait(Some(10)).unwrap();
345+
assert_eq!(iter.next(), None);
346+
300347
// As the `EventManager::wait` should timeout the value of the atomic boolean should not be
301348
// flipped.
302349
assert!(COUNT.load(Ordering::SeqCst));
@@ -329,15 +376,18 @@ mod tests {
329376
assert!(!COUNT.load(Ordering::SeqCst));
330377

331378
// As the closure will flip the atomic boolean we assert it has flipped correctly.
332-
let vec = vec![()];
333-
assert_eq!(manager.wait(Some(10)), Ok(vec.as_slice()));
379+
let mut iter = manager.wait(Some(10)).unwrap();
380+
assert_eq!(iter.next(), Some(&mut ()));
381+
assert_eq!(iter.next(), None);
382+
334383
// As the closure will flip the atomic boolean we assert it has flipped correctly.
335384
assert!(COUNT.load(Ordering::SeqCst));
336385

337386
// The file descriptor has been pre-armed, this will immediately call the respective
338387
// closure.
339-
let vec = vec![()];
340-
assert_eq!(manager.wait(Some(10)), Ok(vec.as_slice()));
388+
let mut iter = manager.wait(Some(10)).unwrap();
389+
assert_eq!(iter.next(), Some(&mut ()));
390+
assert_eq!(iter.next(), None);
341391
// As the closure will flip the atomic boolean we assert it has flipped correctly.
342392
assert!(!COUNT.load(Ordering::SeqCst));
343393
}
@@ -394,8 +444,12 @@ mod tests {
394444
}
395445

396446
// Check counter are the correct values
397-
let arr = [0; FIRING];
398-
assert_eq!(manager.wait(None), Ok(arr.as_slice()));
447+
let mut iter = manager.wait(None).unwrap();
448+
for _ in 0..FIRING {
449+
assert_eq!(iter.next(), Some(&mut 0));
450+
}
451+
assert_eq!(iter.next(), None);
452+
399453
for i in set {
400454
assert_eq!(subscribers[i].1.load(Ordering::SeqCst), 1);
401455
}
@@ -429,7 +483,9 @@ mod tests {
429483
.add(event_fd, EventSet::IN, Box::new(|_, _| Err(())))
430484
.unwrap();
431485

432-
let arr = [Ok(()), Err(())];
433-
assert_eq!(manager.wait(None), Ok(arr.as_slice()));
486+
let mut iter = manager.wait(None).unwrap();
487+
assert_eq!(iter.next(), Some(&mut Ok(())));
488+
assert_eq!(iter.next(), Some(&mut Err(())));
489+
assert_eq!(iter.next(), None);
434490
}
435491
}

0 commit comments

Comments
 (0)