use crate::MAX_PO;
use derive_more::{Display, Into};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[repr(transparent)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Display, Into)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
#[display("po={_0}")]
#[into(u8, usize)]
pub struct ProximityOrder(u8);
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
pub enum ProximityOrderError {
#[error("proximity order {raw} exceeds MAX_PO ({max})")]
OutOfRange {
raw: u8,
max: u8,
},
}
impl ProximityOrder {
pub const MIN: Self = Self(0);
pub const MAX: Self = Self(MAX_PO);
#[inline]
pub(crate) const fn new_unchecked(raw: u8) -> Self {
debug_assert!(raw <= MAX_PO);
Self(raw)
}
#[inline]
pub const fn new(raw: u8) -> Result<Self, ProximityOrderError> {
if raw <= MAX_PO {
Ok(Self(raw))
} else {
Err(ProximityOrderError::OutOfRange { raw, max: MAX_PO })
}
}
#[inline]
pub const fn get(self) -> u8 {
self.0
}
}
impl TryFrom<u8> for ProximityOrder {
type Error = ProximityOrderError;
fn try_from(raw: u8) -> Result<Self, Self::Error> {
Self::new(raw)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn min_max_consts() {
assert_eq!(ProximityOrder::MIN.get(), 0);
assert_eq!(ProximityOrder::MAX.get(), MAX_PO);
}
#[test]
fn new_in_range_ok() {
assert!(ProximityOrder::new(0).is_ok());
assert!(ProximityOrder::new(MAX_PO).is_ok());
}
#[test]
fn new_out_of_range_errs() {
let err = ProximityOrder::new(MAX_PO + 1).unwrap_err();
assert!(matches!(
err,
ProximityOrderError::OutOfRange { raw: 32, max: 31 }
));
}
#[test]
fn display_shows_po() {
assert_eq!(format!("{}", ProximityOrder::new(7).unwrap()), "po=7");
}
#[test]
fn try_from_byte() {
let po: ProximityOrder = 5u8.try_into().unwrap();
assert_eq!(po.get(), 5);
}
}