#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Priority(i16);
pub const MIN_PRIORITY: i16 = 0;
pub const MAX_PRIORITY: i16 = 32767;
impl Priority {
#[must_use]
pub fn new(value: i16) -> Option<Self> {
if (MIN_PRIORITY..=MAX_PRIORITY).contains(&value) {
Some(Self(value))
} else {
None
}
}
#[must_use]
pub fn clamped(value: i32) -> Self {
Self(value.clamp(MIN_PRIORITY as i32, MAX_PRIORITY as i32) as i16)
}
#[must_use]
pub fn value(self) -> i16 {
self.0
}
}
pub trait PriorityMapping {
fn to_native(&self, corba: Priority) -> Option<i32>;
fn to_corba(&self, native: i32) -> Option<Priority>;
}
#[derive(Debug, Clone, Copy)]
pub struct LinearPriorityMapping {
native_min: i32,
native_max: i32,
}
impl LinearPriorityMapping {
#[must_use]
pub fn new(native_min: i32, native_max: i32) -> Self {
Self {
native_min,
native_max,
}
}
}
impl PriorityMapping for LinearPriorityMapping {
fn to_native(&self, corba: Priority) -> Option<i32> {
let span = i64::from(self.native_max - self.native_min);
let scaled = i64::from(corba.value()) * span / i64::from(MAX_PRIORITY);
Some(self.native_min + scaled as i32)
}
fn to_corba(&self, native: i32) -> Option<Priority> {
if native < self.native_min || native > self.native_max {
return None;
}
let span = i64::from(self.native_max - self.native_min);
if span == 0 {
return Priority::new(0);
}
let scaled = i64::from(native - self.native_min) * i64::from(MAX_PRIORITY) / span;
Priority::new(scaled as i16)
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::panic)]
mod tests {
use super::*;
#[test]
fn priority_range() {
assert!(Priority::new(0).is_some());
assert!(Priority::new(32767).is_some());
assert!(Priority::new(-1).is_none());
assert_eq!(Priority::clamped(99999).value(), 32767);
assert_eq!(Priority::clamped(-5).value(), 0);
}
#[test]
fn linear_mapping_endpoints() {
let m = LinearPriorityMapping::new(1, 99);
assert_eq!(m.to_native(Priority::new(0).unwrap()), Some(1));
assert_eq!(m.to_native(Priority::new(32767).unwrap()), Some(99)); let mid = m.to_native(Priority::new(16383).unwrap()).unwrap();
assert!((49..=51).contains(&mid), "mid={mid}");
}
#[test]
fn native_out_of_window_unmapped() {
let m = LinearPriorityMapping::new(1, 99);
assert!(m.to_corba(0).is_none());
assert!(m.to_corba(100).is_none());
assert!(m.to_corba(50).is_some());
}
}