#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum QueueStrategy {
Fifo,
Lifo,
}
#[derive(Debug, Clone)]
pub(crate) enum PriorityRule {
Default(QueueStrategy),
Exact(isize, QueueStrategy),
Range(isize, isize, QueueStrategy),
}
#[derive(Debug, Clone)]
pub struct PriorityConfig {
pub(crate) rules: Vec<PriorityRule>,
}
impl PriorityConfig {
pub fn new() -> Self {
Self { rules: Vec::new() }
}
pub fn default_strategy(mut self, strategy: QueueStrategy) -> Self {
self.rules.push(PriorityRule::Default(strategy));
self
}
pub fn exact(mut self, priority: isize, strategy: QueueStrategy) -> Self {
self.rules.push(PriorityRule::Exact(priority, strategy));
self
}
pub fn greater_or_equal(mut self, threshold: isize, strategy: QueueStrategy) -> Self {
self.rules
.push(PriorityRule::Range(threshold, isize::MAX, strategy));
self
}
pub fn greater_than(mut self, threshold: isize, strategy: QueueStrategy) -> Self {
let min = threshold.saturating_add(1);
self.rules
.push(PriorityRule::Range(min, isize::MAX, strategy));
self
}
pub fn less_or_equal(mut self, threshold: isize, strategy: QueueStrategy) -> Self {
self.rules
.push(PriorityRule::Range(isize::MIN, threshold, strategy));
self
}
pub fn less_than(mut self, threshold: isize, strategy: QueueStrategy) -> Self {
let max = threshold.saturating_sub(1);
self.rules
.push(PriorityRule::Range(isize::MIN, max, strategy));
self
}
pub fn range(mut self, min: isize, max: isize, strategy: QueueStrategy) -> Self {
self.rules.push(PriorityRule::Range(min, max, strategy));
self
}
pub(crate) fn resolve_strategy(&self, priority: isize) -> QueueStrategy {
let mut default_strategy = QueueStrategy::Fifo;
for rule in &self.rules {
match rule {
PriorityRule::Exact(p, strategy) if *p == priority => return *strategy,
PriorityRule::Default(strategy) => default_strategy = *strategy,
_ => {}
}
}
for rule in &self.rules {
match rule {
PriorityRule::Range(min, max, strategy) if priority >= *min && priority <= *max => {
return *strategy
}
_ => {}
}
}
default_strategy
}
pub fn strategy_for_priority(&self, priority: isize) -> QueueStrategy {
self.resolve_strategy(priority)
}
}
impl Default for PriorityConfig {
fn default() -> Self {
Self::new().default_strategy(QueueStrategy::Fifo)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_exact_match() {
let config = PriorityConfig::new()
.default_strategy(QueueStrategy::Fifo)
.exact(5, QueueStrategy::Lifo);
assert_eq!(config.resolve_strategy(5), QueueStrategy::Lifo);
assert_eq!(config.resolve_strategy(4), QueueStrategy::Fifo);
assert_eq!(config.resolve_strategy(6), QueueStrategy::Fifo);
}
#[test]
fn test_range_match() {
let config = PriorityConfig::new()
.default_strategy(QueueStrategy::Fifo)
.range(1, 10, QueueStrategy::Lifo);
assert_eq!(config.resolve_strategy(0), QueueStrategy::Fifo);
assert_eq!(config.resolve_strategy(1), QueueStrategy::Lifo);
assert_eq!(config.resolve_strategy(5), QueueStrategy::Lifo);
assert_eq!(config.resolve_strategy(10), QueueStrategy::Lifo);
assert_eq!(config.resolve_strategy(11), QueueStrategy::Fifo);
}
#[test]
fn test_greater_or_equal() {
let config = PriorityConfig::new()
.default_strategy(QueueStrategy::Fifo)
.greater_or_equal(5, QueueStrategy::Lifo);
assert_eq!(config.resolve_strategy(4), QueueStrategy::Fifo);
assert_eq!(config.resolve_strategy(5), QueueStrategy::Lifo);
assert_eq!(config.resolve_strategy(10), QueueStrategy::Lifo);
}
#[test]
fn test_greater_than() {
let config = PriorityConfig::new()
.default_strategy(QueueStrategy::Fifo)
.greater_than(5, QueueStrategy::Lifo);
assert_eq!(config.resolve_strategy(5), QueueStrategy::Fifo);
assert_eq!(config.resolve_strategy(6), QueueStrategy::Lifo);
assert_eq!(config.resolve_strategy(10), QueueStrategy::Lifo);
}
#[test]
fn test_less_or_equal() {
let config = PriorityConfig::new()
.default_strategy(QueueStrategy::Lifo)
.less_or_equal(0, QueueStrategy::Fifo);
assert_eq!(config.resolve_strategy(-5), QueueStrategy::Fifo);
assert_eq!(config.resolve_strategy(0), QueueStrategy::Fifo);
assert_eq!(config.resolve_strategy(1), QueueStrategy::Lifo);
}
#[test]
fn test_less_than() {
let config = PriorityConfig::new()
.default_strategy(QueueStrategy::Fifo)
.less_than(0, QueueStrategy::Lifo);
assert_eq!(config.resolve_strategy(-5), QueueStrategy::Lifo);
assert_eq!(config.resolve_strategy(0), QueueStrategy::Fifo);
assert_eq!(config.resolve_strategy(1), QueueStrategy::Fifo);
}
#[test]
fn test_priority_order() {
let config = PriorityConfig::new()
.default_strategy(QueueStrategy::Fifo)
.greater_or_equal(5, QueueStrategy::Lifo)
.exact(10, QueueStrategy::Fifo);
assert_eq!(config.resolve_strategy(5), QueueStrategy::Lifo);
assert_eq!(config.resolve_strategy(8), QueueStrategy::Lifo);
assert_eq!(config.resolve_strategy(10), QueueStrategy::Fifo); }
#[test]
fn test_multiple_thresholds() {
let config = PriorityConfig::new()
.default_strategy(QueueStrategy::Fifo)
.range(5, isize::MAX, QueueStrategy::Lifo)
.range(10, isize::MAX, QueueStrategy::Fifo);
assert_eq!(config.resolve_strategy(4), QueueStrategy::Fifo);
assert_eq!(config.resolve_strategy(7), QueueStrategy::Lifo);
assert_eq!(config.resolve_strategy(15), QueueStrategy::Lifo);
}
}