use crate::SubUsizeExt;
const LIMBO_SLOTS: u8 = 16;
pub(crate) type MaybeReject<T> = Result<(), T>;
#[allow(clippy::as_conversions)]
pub(crate) struct LimboPool<S> {
senders: [Option<S>; LIMBO_SLOTS as _],
count: u8,
count_including_overflow: usize,
}
impl<S> LimboPool<S> {
fn incr_count_including_overflow(&mut self) {
self.count_including_overflow = self.count_including_overflow.saturating_add(1);
}
pub fn add_sender(&mut self, s: S) -> MaybeReject<S> {
self.incr_count_including_overflow();
#[allow(clippy::arithmetic_side_effects, clippy::indexing_slicing)]
if self.count < LIMBO_SLOTS {
self.senders[self.count.to_usize()] = Some(s);
self.count += 1;
Ok(())
} else {
Err(s)
}
}
#[allow(clippy::unwrap_used, clippy::unwrap_in_result)] pub fn linear_try<T>(
&mut self,
acc: T,
mut f: impl FnMut(&mut S, T) -> MaybeReject<T>,
) -> MaybeReject<T> {
let mut acc = Some(acc);
#[allow(clippy::indexing_slicing)]
for sender in &mut self.senders[0..(usize::from(self.count))] {
let regain = match f(sender.as_mut().unwrap(), acc.take().unwrap()) {
Ok(()) => return Ok(()),
Err(r) => r,
};
acc = Some(regain);
}
Err(acc.unwrap())
}
pub fn linear_try_or_create<T>(
&mut self,
acc: T,
tryf: impl FnMut(&mut S, T) -> MaybeReject<T>,
createf: impl FnOnce(usize, T) -> S,
fullf: impl FnOnce(usize, T),
) {
let acc = match self.linear_try(acc, tryf) {
Ok(()) => return,
Err(regain) => regain,
};
if self.count < LIMBO_SLOTS {
let _ = self.add_sender(createf(self.count.into(), acc));
} else {
fullf(self.count_including_overflow, acc);
self.incr_count_including_overflow();
}
}
}
impl<S> Default for LimboPool<S> {
fn default() -> Self {
Self {
senders: Default::default(),
count: 0,
count_including_overflow: 0,
}
}
}