use crate::calendar::{DefaultPlan, Scheduler};
use core::{any::Any, fmt, marker::PhantomData};
#[doc(inline)]
pub use odem_rs_meta::Config;
pub trait Config: 'static {
type Time: Time;
type Rank: Rank;
type Data: Any;
type Plan: Scheduler<Config = Self>;
fn default_time(&self) -> Self::Time;
fn default_rank(&self) -> Self::Rank;
fn global_data(&self) -> &Self::Data;
}
pub trait Time: Unpin + PartialOrd + Copy + fmt::Debug + 'static {
fn format(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self, f)
}
fn display(self) -> DisplayTime<Self> {
DisplayTime(self)
}
}
pub trait Rank: Unpin + Ord + Copy + fmt::Debug + 'static {}
impl<R> Rank for R where R: Unpin + Ord + Copy + fmt::Debug + 'static {}
impl Config for () {
type Time = f64;
type Rank = ();
type Data = ();
type Plan = DefaultPlan<()>;
fn default_time(&self) -> Self::Time {
0.0
}
fn default_rank(&self) -> Self::Rank {}
fn global_data(&self) -> &Self::Data {
self
}
}
pub struct DisplayTime<T>(pub T);
impl<T: Time> fmt::Debug for DisplayTime<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.format(f)
}
}
impl<T: Time> fmt::Display for DisplayTime<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.format(f)
}
}
macro_rules! impl_signed_integral_time {
($($T:ty),* $(,)?) => {$(
impl Time for $T {
fn format(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use fmt::Display;
if f.alternate() {
Display::fmt(&ClockTime::seconds(*self as isize), f)
} else {
Display::fmt(self, f)
}
}
}
)*};
}
impl_signed_integral_time!(i8, i16, i32, i64, i128, isize);
macro_rules! impl_unsigned_integral_time {
($($T:ty),* $(,)?) => {$(
impl Time for $T {
fn format(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use fmt::Display;
if f.alternate() {
Display::fmt(&Seconds(*self as usize), f)
} else {
Display::fmt(self, f)
}
}
}
)*};
}
impl_unsigned_integral_time!(u8, u16, u32, u64, u128, usize);
macro_rules! impl_floating_time {
($($T:ty),* $(,)?) => {$(
impl Time for $T {
fn format(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use fmt::Display;
if f.alternate() {
match f.precision() {
None | Some(0) => Display::fmt(&ClockTime::seconds(*self as isize), f),
Some(1) => Display::fmt(&ClockTime::milliseconds((*self * 1e+3) as isize), f),
Some(2) => Display::fmt(&ClockTime::microseconds((*self * 1e+6) as isize), f),
_ => Display::fmt(&ClockTime::nanoseconds((*self * 1e+9) as isize), f),
}
} else {
Display::fmt(self, f)
}
}
}
)*};
}
impl_floating_time!(f32, f64);
impl Time for () {}
#[derive(Copy, Clone)]
pub struct ClockTime<U> {
value: isize,
_unit: PhantomData<U>,
}
impl ClockTime<()> {
pub const fn nanoseconds(value: isize) -> impl fmt::Display {
ClockTime::<Nanoseconds> {
value,
_unit: PhantomData,
}
}
pub const fn microseconds(value: isize) -> impl fmt::Display {
ClockTime::<Microseconds> {
value,
_unit: PhantomData,
}
}
pub const fn milliseconds(value: isize) -> impl fmt::Display {
ClockTime::<Milliseconds> {
value,
_unit: PhantomData,
}
}
pub const fn seconds(value: isize) -> impl fmt::Display {
ClockTime::<Seconds> {
value,
_unit: PhantomData,
}
}
pub const fn minutes(value: isize) -> impl fmt::Display {
ClockTime::<Minutes> {
value,
_unit: PhantomData,
}
}
pub const fn hours(value: isize) -> impl fmt::Display {
ClockTime::<Hours> {
value,
_unit: PhantomData,
}
}
pub const fn days(value: isize) -> impl fmt::Display {
ClockTime::<Days> {
value,
_unit: PhantomData,
}
}
pub const fn years(value: isize) -> impl fmt::Display {
ClockTime::<Years> {
value,
_unit: PhantomData,
}
}
}
impl<U> ClockTime<U> {
fn write_sign(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.value < 0 {
write!(f, "-")
} else if f.sign_plus() {
write!(f, "+")
} else {
Ok(())
}
}
}
impl fmt::Display for ClockTime<Years> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.write_sign(f)?;
Years(self.value.unsigned_abs()).fmt(f)
}
}
impl fmt::Display for ClockTime<Days> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.write_sign(f)?;
Days(self.value.unsigned_abs()).fmt(f)
}
}
impl fmt::Display for ClockTime<Hours> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.write_sign(f)?;
Hours(self.value.unsigned_abs()).fmt(f)
}
}
impl fmt::Display for ClockTime<Minutes> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.write_sign(f)?;
Minutes(self.value.unsigned_abs()).fmt(f)
}
}
impl fmt::Display for ClockTime<Seconds> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.write_sign(f)?;
Seconds(self.value.unsigned_abs()).fmt(f)
}
}
impl fmt::Display for ClockTime<Milliseconds> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.write_sign(f)?;
Milliseconds(self.value.unsigned_abs()).fmt(f)
}
}
impl fmt::Display for ClockTime<Microseconds> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.write_sign(f)?;
Microseconds(self.value.unsigned_abs()).fmt(f)
}
}
impl fmt::Display for ClockTime<Nanoseconds> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.write_sign(f)?;
Nanoseconds(self.value.unsigned_abs()).fmt(f)
}
}
struct Nanoseconds(usize);
struct Microseconds(usize);
struct Milliseconds(usize);
struct Seconds(usize);
struct Minutes(usize);
struct Hours(usize);
struct Days(usize);
struct Years(usize);
impl fmt::Display for Years {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.0 != 0 || f.sign_aware_zero_pad() {
write!(f, "{}a", self.0)
} else {
f.write_str(" ")
}
}
}
impl fmt::Display for Days {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut quantity = self.0;
let mut p;
if {
p = quantity >= 365;
p
} || f.width().map(|w| w > 5).unwrap_or(false)
{
Years(quantity / 365).fmt(f)?;
f.write_str(" ")?;
}
if quantity >= 7 || f.width().map(|w| w > 4).unwrap_or(false) {
quantity %= 365;
p |= quantity >= 7;
if p || f.sign_aware_zero_pad() {
write!(f, "{:2}w ", quantity / 7)?;
} else {
f.write_str(" ")?;
}
quantity %= 7;
}
if p || quantity != 0 || f.sign_aware_zero_pad() {
write!(f, "{quantity}d")
} else {
f.write_str(" ")
}
}
}
impl fmt::Display for Hours {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut quantity = self.0;
let p;
if {
p = quantity >= 24;
p
} || f.width().map(|w| w > 3).unwrap_or(false)
{
Days(quantity / 24).fmt(f)?;
quantity %= 24;
f.write_str(" ")?;
}
if p || quantity != 0 || f.sign_aware_zero_pad() {
write!(f, "{quantity:02}h")
} else {
f.write_str(" ")
}
}
}
impl fmt::Display for Minutes {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut quantity = self.0;
let p;
if {
p = quantity >= 60;
p
} || f.width().map(|w| w > 2).unwrap_or(false)
{
Hours(quantity / 60).fmt(f)?;
quantity %= 60;
f.write_str(" ")?;
}
if p || quantity != 0 || f.sign_aware_zero_pad() {
write!(f, "{quantity:02}m")
} else {
f.write_str(" ")
}
}
}
impl fmt::Display for Seconds {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut quantity = self.0;
let p;
if {
p = quantity >= 60;
p
} || f.width().map(|w| w > 1).unwrap_or(false)
{
Minutes(quantity / 60).fmt(f)?;
quantity %= 60;
f.write_str(" ")?;
}
if p || quantity != 0 || f.sign_aware_zero_pad() {
write!(f, "{quantity:02}s")
} else {
f.write_str(" 0s")
}
}
}
impl fmt::Display for Milliseconds {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut quantity = self.0;
Seconds(quantity / 1000).fmt(f)?;
quantity %= 1000;
write!(f, " {quantity:03}ms")
}
}
impl fmt::Display for Microseconds {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut quantity = self.0;
Milliseconds(quantity / 1000).fmt(f)?;
quantity %= 1000;
write!(f, " {quantity:03}µs")
}
}
impl fmt::Display for Nanoseconds {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut quantity = self.0;
Microseconds(quantity / 1000).fmt(f)?;
quantity %= 1000;
write!(f, " {quantity:03}ns")
}
}
#[cfg(feature = "uom")]
#[cfg_attr(docsrs, doc(cfg(feature = "uom")))]
mod uom {
use super::{ClockTime, Time};
use core::fmt;
use uom::{
Conversion,
fmt::DisplayStyle,
num_traits::{AsPrimitive, Num},
si::{Units, time},
};
impl<U, V> Time for time::Time<U, V>
where
U: Units<V> + ?Sized + 'static,
V: Conversion<V>
+ Num
+ PartialOrd
+ PartialEq
+ AsPrimitive<isize>
+ fmt::Debug
+ fmt::Display
+ Unpin
+ 'static,
time::second: Conversion<V, T = V::T>,
time::millisecond: Conversion<V, T = V::T>,
time::microsecond: Conversion<V, T = V::T>,
time::nanosecond: Conversion<V, T = V::T>,
{
fn format(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use fmt::Display;
if f.alternate() {
match f.precision() {
None | Some(0) => ClockTime::seconds(self.get::<time::second>().as_()).fmt(f),
Some(1) => {
ClockTime::milliseconds(self.get::<time::millisecond>().as_()).fmt(f)
}
Some(2) => {
ClockTime::microseconds(self.get::<time::microsecond>().as_()).fmt(f)
}
_ => ClockTime::nanoseconds(self.get::<time::nanosecond>().as_()).fmt(f),
}
} else {
self.into_format_args(time::second, DisplayStyle::Abbreviation)
.fmt(f)
}
}
}
}