#![forbid(unsafe_code)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) enum AdmissionError {
Capacity,
IdentityExhausted,
DeadlineOverflow,
}
pub(crate) fn deadline(now: u64, delay: std::time::Duration) -> Result<u64, AdmissionError> {
u64::try_from(delay.as_nanos())
.ok()
.and_then(|delay| now.checked_add(delay))
.ok_or(AdmissionError::DeadlineOverflow)
}
struct Pending<T> {
id: u64,
deadline: u64,
submitted: bool,
value: T,
}
pub(crate) struct Queue<T, const CAPACITY: usize> {
entries: Vec<Pending<T>>,
last_id: u64,
}
impl<T, const CAPACITY: usize> Queue<T, CAPACITY> {
pub(crate) const fn new() -> Self {
Self {
entries: Vec::new(),
last_id: 0,
}
}
pub(crate) fn insert(&mut self, deadline: u64, value: T) -> Result<u64, (AdmissionError, T)> {
if self.entries.len() == CAPACITY {
return Err((AdmissionError::Capacity, value));
}
let Some(id) = self.last_id.checked_add(1) else {
return Err((AdmissionError::IdentityExhausted, value));
};
self.entries.push(Pending {
id,
deadline,
submitted: false,
value,
});
self.last_id = id;
Ok(id)
}
pub(crate) fn next(&self) -> Option<(u64, u64)> {
self.entries
.iter()
.filter(|entry| !entry.submitted)
.map(|entry| (entry.deadline, entry.id))
.min()
}
pub(crate) fn submit(&mut self, id: u64) {
if let Some(entry) = self.entries.iter_mut().find(|entry| entry.id == id) {
entry.submitted = true;
}
}
pub(crate) fn retry(&mut self, id: u64, deadline: u64) {
if let Some(entry) = self.entries.iter_mut().find(|entry| entry.id == id) {
entry.submitted = false;
entry.deadline = deadline;
}
}
pub(crate) fn remove(&mut self, id: u64) -> Option<T> {
let index = self.entries.iter().position(|entry| entry.id == id)?;
Some(self.entries.swap_remove(index).value)
}
}
#[cfg(test)]
mod tests;