use crate::error::BticError;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[repr(u8)]
pub enum Granularity {
Millisecond = 0,
Second = 1,
Minute = 2,
Hour = 3,
Day = 4,
Month = 5,
Quarter = 6,
Year = 7,
Decade = 8,
Century = 9,
Millennium = 10,
}
impl Granularity {
pub fn from_code(code: u8) -> Result<Self, BticError> {
match code {
0 => Ok(Self::Millisecond),
1 => Ok(Self::Second),
2 => Ok(Self::Minute),
3 => Ok(Self::Hour),
4 => Ok(Self::Day),
5 => Ok(Self::Month),
6 => Ok(Self::Quarter),
7 => Ok(Self::Year),
8 => Ok(Self::Decade),
9 => Ok(Self::Century),
10 => Ok(Self::Millennium),
_ => Err(BticError::GranularityRange(code)),
}
}
pub fn code(self) -> u8 {
self as u8
}
pub fn name(self) -> &'static str {
match self {
Self::Millisecond => "millisecond",
Self::Second => "second",
Self::Minute => "minute",
Self::Hour => "hour",
Self::Day => "day",
Self::Month => "month",
Self::Quarter => "quarter",
Self::Year => "year",
Self::Decade => "decade",
Self::Century => "century",
Self::Millennium => "millennium",
}
}
pub fn from_name(s: &str) -> Option<Self> {
match s.to_lowercase().as_str() {
"millisecond" | "ms" => Some(Self::Millisecond),
"second" | "s" => Some(Self::Second),
"minute" | "min" => Some(Self::Minute),
"hour" | "h" => Some(Self::Hour),
"day" | "d" => Some(Self::Day),
"month" | "mon" => Some(Self::Month),
"quarter" | "q" => Some(Self::Quarter),
"year" | "y" => Some(Self::Year),
"decade" => Some(Self::Decade),
"century" => Some(Self::Century),
"millennium" => Some(Self::Millennium),
_ => None,
}
}
pub fn finer(self, other: Self) -> Self {
std::cmp::min(self, other)
}
}
impl std::fmt::Display for Granularity {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.name())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn roundtrip_all_codes() {
for code in 0..=10u8 {
let g = Granularity::from_code(code).unwrap();
assert_eq!(g.code(), code);
}
}
#[test]
fn reserved_codes_rejected() {
for code in 11..=15u8 {
assert!(Granularity::from_code(code).is_err());
}
}
#[test]
fn name_roundtrip() {
for code in 0..=10u8 {
let g = Granularity::from_code(code).unwrap();
let g2 = Granularity::from_name(g.name()).unwrap();
assert_eq!(g, g2);
}
}
#[test]
fn finer_picks_lower_code() {
assert_eq!(Granularity::Day.finer(Granularity::Year), Granularity::Day);
assert_eq!(
Granularity::Year.finer(Granularity::Month),
Granularity::Month
);
assert_eq!(
Granularity::Millisecond.finer(Granularity::Millennium),
Granularity::Millisecond
);
}
}