use std::fmt::{Display, Formatter, Result as FmtResult};
use std::str::FromStr;
use crate::enums::error::MinarrowError;
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug, Default)]
pub enum TimeUnit {
Seconds,
Milliseconds,
Microseconds,
Nanoseconds,
#[default]
Days,
}
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
pub enum IntervalUnit {
YearMonth,
DaysTime,
MonthDaysNs,
}
impl Display for TimeUnit {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
TimeUnit::Seconds => f.write_str("Seconds"),
TimeUnit::Milliseconds => f.write_str("Milliseconds"),
TimeUnit::Microseconds => f.write_str("Microseconds"),
TimeUnit::Nanoseconds => f.write_str("Nanoseconds"),
TimeUnit::Days => f.write_str("Days"),
}
}
}
impl Display for IntervalUnit {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
IntervalUnit::YearMonth => f.write_str("YearMonth"),
IntervalUnit::DaysTime => f.write_str("DaysTime"),
IntervalUnit::MonthDaysNs => f.write_str("MonthDaysNs"),
}
}
}
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
pub enum TimePeriod {
Year,
Month,
Week,
Day,
Hour,
Minute,
Second,
Millisecond,
Microsecond,
}
impl TimePeriod {
pub const fn as_str(&self) -> &'static str {
match self {
TimePeriod::Year => "year",
TimePeriod::Month => "month",
TimePeriod::Week => "week",
TimePeriod::Day => "day",
TimePeriod::Hour => "hour",
TimePeriod::Minute => "minute",
TimePeriod::Second => "second",
TimePeriod::Millisecond => "millisecond",
TimePeriod::Microsecond => "microsecond",
}
}
}
impl Display for TimePeriod {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
f.write_str(self.as_str())
}
}
impl FromStr for TimePeriod {
type Err = MinarrowError;
fn from_str(value: &str) -> Result<Self, Self::Err> {
match value {
"year" => Ok(TimePeriod::Year),
"month" => Ok(TimePeriod::Month),
"week" => Ok(TimePeriod::Week),
"day" => Ok(TimePeriod::Day),
"hour" => Ok(TimePeriod::Hour),
"minute" => Ok(TimePeriod::Minute),
"second" => Ok(TimePeriod::Second),
"millisecond" => Ok(TimePeriod::Millisecond),
"microsecond" => Ok(TimePeriod::Microsecond),
other => Err(MinarrowError::TypeError {
from: "String",
to: "TimePeriod",
message: Some(format!("Unknown time period: {}", other)),
}),
}
}
}
impl From<&str> for TimePeriod {
fn from(value: &str) -> Self {
value.parse().unwrap_or_else(|e| panic!("{}", e))
}
}
#[cfg(test)]
mod time_period_tests {
use super::TimePeriod;
#[test]
fn label_round_trips_through_string() {
for period in [
TimePeriod::Year,
TimePeriod::Month,
TimePeriod::Week,
TimePeriod::Day,
TimePeriod::Hour,
TimePeriod::Minute,
TimePeriod::Second,
TimePeriod::Millisecond,
TimePeriod::Microsecond,
] {
assert_eq!(period.as_str().parse::<TimePeriod>().unwrap(), period);
assert_eq!(period.to_string(), period.as_str());
}
}
#[test]
fn from_str_accepts_known_label() {
assert_eq!("day".parse::<TimePeriod>().unwrap(), TimePeriod::Day);
assert_eq!(TimePeriod::from("week"), TimePeriod::Week);
}
#[test]
fn parse_rejects_unknown_label() {
assert!("fortnight".parse::<TimePeriod>().is_err());
}
#[test]
#[should_panic]
fn from_panics_on_unknown_label() {
let _ = TimePeriod::from("fortnight");
}
}