#![expect(clippy::indexing_slicing, reason = "module is scheduled for overhaul")]
#![expect(
clippy::doc_paragraphs_missing_punctuation,
reason = "module is scheduled for overhaul"
)]
#![expect(clippy::pedantic)]
use arrayvec::ArrayVec;
pub trait PriorityLevel {
fn level(&self) -> usize;
}
#[derive(Debug)]
pub struct OrderedPool<T: PriorityLevel, const N: usize, const L: usize> {
pub entries: ArrayVec<T, N>,
pub sorted: ArrayVec<u16, N>,
}
impl<T: PriorityLevel, const N: usize, const L: usize> OrderedPool<T, N, L> {
#[must_use]
pub const fn new() -> Self {
assert!(N < u16::MAX as usize, "Capacity overflow");
assert!(L < u16::MAX as usize, "Level overflow");
OrderedPool {
entries: ArrayVec::new_const(),
sorted: ArrayVec::new_const(),
}
}
pub fn lookup<Ftest, Fuse, R>(&mut self, mut f_test: Ftest, f_use: Fuse) -> Option<R>
where
Ftest: FnMut(&T) -> bool,
Fuse: FnOnce(&mut T) -> R,
{
for (position, &index) in self.sorted.iter().enumerate() {
if f_test(&self.entries[usize::from(index)]) {
let r = f_use(&mut self.entries[usize::from(index)]);
self.touch(position);
return Some(r);
}
}
None
}
#[allow(
dead_code,
reason = "Need for this function is unclear, but it is covered in tests and docs, and may easily be needed again as coapcore is being refactored."
)]
pub fn insert(&mut self, new: T) -> Result<Option<T>, T> {
let new_index = self.entries.len();
if new_index < N {
self.entries.push(new);
self.sorted.push(
new_index
.try_into()
.expect("Range is checked at construction time"),
);
self.touch(new_index);
Ok(None)
} else {
let last_slot = &mut self.entries
[usize::from(*self.sorted.last().expect("Full array is not empty"))];
let last_level = last_slot.level();
let new_level = new.level();
debug_assert!(new_level < L, "Level exceeds limit L={L} in type");
if new_level <= last_level {
let last = core::mem::replace(last_slot, new);
self.touch(N - 1);
Ok(Some(last))
} else {
Err(new)
}
}
}
pub fn force_insert(&mut self, new: T) -> Option<T> {
let new_index = self.entries.len();
if new_index < N {
self.entries.push(new);
self.sorted.push(
new_index
.try_into()
.expect("Range is checked at construction time"),
);
self.touch(new_index);
None
} else {
let last_slot = &mut self.entries
[usize::from(*self.sorted.last().expect("Full array is not empty"))];
let last = core::mem::replace(last_slot, new);
self.touch(N - 1);
Some(last)
}
}
fn touch(&mut self, position: usize) {
let level = self.entries[usize::from(self.sorted[position])].level();
debug_assert!(level < L, "Level exceeds limit L={L} in type");
let mut new_position = position;
while new_position
.checked_sub(1)
.is_some_and(|n| self.entries[usize::from(self.sorted[n])].level() >= level)
{
new_position -= 1;
}
if new_position == position {
while new_position < self.sorted.len() - 1
&& self.entries[usize::from(self.sorted[new_position + 1])].level() < level
{
new_position += 1;
}
if new_position != position {
self.sorted[position..=new_position].rotate_left(1);
}
} else {
self.sorted[new_position..=position].rotate_right(1);
}
}
pub(crate) fn iter(&self) -> impl Iterator<Item = &T> {
self.entries.iter()
}
}
impl<T: PriorityLevel, const N: usize, const L: usize> core::default::Default
for OrderedPool<T, N, L>
{
fn default() -> Self {
Self::new()
}
}