mod frac_int;
mod raw;
use crate::prelude::*;
use std::ops::{Div, DivAssign, Mul, MulAssign};
pub use frac_int::FracInt;
pub use raw::RawTime;
#[derive(
Clone,
Copy,
Debug,
PartialEq,
Eq,
PartialOrd,
Ord,
derive_more::Add,
derive_more::AddAssign,
derive_more::Sub,
derive_more::SubAssign,
derive_more::Rem,
derive_more::RemAssign,
derive_more::Sum,
)]
#[rem(forward)]
pub struct Time {
pub samples: FracInt,
}
impl Time {
pub const ZERO: Self = Self::new(FracInt::ZERO);
pub const SAMPLE: Self = Self::new(FracInt::ONE);
pub const MAX: Self = Self::new(FracInt::MAX);
#[must_use]
pub const fn new(samples: FracInt) -> Self {
Self { samples }
}
#[must_use]
pub const fn is_zero(self) -> bool {
self.samples.is_zero()
}
#[must_use]
pub const fn from_samples(samples: u64) -> Self {
Self::new(FracInt::new(samples))
}
#[must_use]
pub fn from_raw(raw: RawTime, sample_rate: unt::SampleRate) -> Self {
raw * sample_rate
}
#[must_use]
pub fn from_raw_default(raw: RawTime) -> Self {
Self::from_raw(raw, unt::SampleRate::default())
}
#[must_use]
pub fn from_sec(seconds: f64, sample_rate: unt::SampleRate) -> Self {
Self::from_raw(RawTime::new(seconds), sample_rate)
}
#[must_use]
pub fn from_sec_default(seconds: f64) -> Self {
Self::from_sec(seconds, unt::SampleRate::default())
}
#[must_use]
pub fn from_msec(millis: f64, sample_rate: unt::SampleRate) -> Self {
Self::from_raw(RawTime::new(millis / 1000.0), sample_rate)
}
#[must_use]
pub fn from_msec_default(millis: f64) -> Self {
Self::from_msec(millis, unt::SampleRate::default())
}
#[must_use]
pub fn into_raw(self, sample_rate: unt::SampleRate) -> RawTime {
self / sample_rate
}
#[must_use]
pub fn into_raw_default(self) -> RawTime {
self.into_raw(unt::SampleRate::default())
}
pub fn advance(&mut self) {
*self += Self::SAMPLE;
}
#[must_use]
pub fn floor(self) -> Self {
Self::new(self.samples.floor())
}
}
impl std::fmt::Display for Time {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let samples = self.samples;
if let Some(precision) = f.precision() {
write!(f, "{samples:.precision$} samples")
} else {
write!(f, "{samples} samples")
}
}
}
macro_rules! impl_mul_div {
($($ty: ty),*) => {$(
impl Mul<Time> for $ty {
type Output = Time;
fn mul(self, rhs: Time) -> Time {
Time::new(self * rhs.samples)
}
}
impl Mul<$ty> for Time {
type Output = Self;
fn mul(self, rhs: $ty) -> Self {
rhs * self
}
}
impl MulAssign<$ty> for Time {
fn mul_assign(&mut self, rhs: $ty) {
*self = *self * rhs
}
}
impl Div<$ty> for Time {
type Output = Self;
fn div(self, rhs: $ty) -> Self {
Self::new(self.samples / rhs)
}
}
impl DivAssign<$ty> for Time {
fn div_assign(&mut self, rhs: $ty) {
*self = *self / rhs
}
}
)*};
}
impl_mul_div!(u8, u16, u32, u64, usize, f64);
impl Div<Time> for Time {
type Output = f64;
fn div(self, rhs: Time) -> f64 {
self.samples / rhs.samples
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn print_raw() {
assert_eq!(format!("{}", RawTime::YR), "31536000s");
let pretty = format!("{:#}", RawTime::YR);
if cfg!(feature = "human-duration") {
assert_eq!(pretty, "1y 0mon 0d 0h 0m 0s 0ms");
} else {
assert_eq!(pretty, "31536000s")
}
}
#[test]
fn print_time() {
let time = Time::from_sec_default(1.0 / 11.0);
assert_eq!(format!("{time}"), "4009.090911865234375 samples");
assert_eq!(format!("{time:.2}"), "4009.09 samples");
assert_eq!(
format!("{}", Time::MAX),
"281474976710655.9999847412109375 samples"
)
}
}