use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
use std::ops::{Add, AddAssign, Neg, Sub, SubAssign};
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
struct Timing(i64 );
impl Timing {
fn from_components(hours: i64, mins: i64, secs: i64, ms: i64) -> Timing {
Timing(ms + 1000 * (secs + 60 * (mins + 60 * hours)))
}
fn from_msecs(ms: i64) -> Timing {
Timing(ms)
}
fn from_csecs(cs: i64) -> Timing {
Timing(cs * 10)
}
fn from_secs(s: i64) -> Timing {
Timing(s * 1000)
}
fn from_mins(mins: i64) -> Timing {
Timing(mins * 1000 * 60)
}
fn from_hours(h: i64) -> Timing {
Timing(h * 1000 * 60 * 60)
}
fn msecs(&self) -> i64 {
self.0
}
fn hours(&self) -> i64 {
self.0 / (60 * 60 * 1000)
}
fn mins_comp(&self) -> i64 {
(self.0 / (60 * 1000)) % 60
}
fn secs_comp(&self) -> i64 {
(self.0 / 1000) % 60
}
fn csecs_comp(&self) -> i64 {
((self.0 / 10) % 100)
}
fn msecs_comp(&self) -> i64 {
(self.0 % 1000)
}
fn is_negative(&self) -> bool {
self.0 < 0
}
}
impl Debug for Timing {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(f, "Timing({})", self.to_string())
}
}
impl Display for Timing {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
let t = if self.0 < 0 { -*self } else { *self };
write!(f,
"{}{}:{:02}:{:02}.{:03}",
if self.0 < 0 { "-" } else { "" },
t.hours(),
t.mins_comp(),
t.secs_comp(),
t.msecs_comp())
}
}
impl Add for Timing {
type Output = Timing;
fn add(self, rhs: Timing) -> Timing {
Timing(self.0 + rhs.0)
}
}
impl Sub for Timing {
type Output = Timing;
fn sub(self, rhs: Timing) -> Timing {
Timing(self.0 - rhs.0)
}
}
impl AddAssign for Timing {
fn add_assign(&mut self, r: Timing) {
self.0 += r.0;
}
}
impl SubAssign for Timing {
fn sub_assign(&mut self, r: Timing) {
self.0 += r.0;
}
}
impl Neg for Timing {
type Output = Timing;
fn neg(self) -> Timing {
Timing(-self.0)
}
}
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct TimePoint {
intern: Timing,
}
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct TimeDelta {
intern: Timing,
}
macro_rules! create_time_type {
($i:ident) => {
impl $i {
fn new(t: Timing) -> $i {
$i { intern: t }
}
pub fn from_components(hours: i64, mins: i64, secs: i64, ms: i64) -> $i {
Self::new(Timing::from_components(hours, mins, secs, ms))
}
pub fn from_msecs(ms: i64) -> $i {
Self::new(Timing::from_msecs(ms))
}
pub fn from_csecs(ms: i64) -> $i {
Self::new(Timing::from_csecs(ms))
}
pub fn from_secs(ms: i64) -> $i {
Self::new(Timing::from_secs(ms))
}
pub fn from_mins(mins: i64) -> $i {
Self::new(Timing::from_mins(mins))
}
pub fn from_hours(mins: i64) -> $i {
Self::new(Timing::from_hours(mins))
}
pub fn msecs(&self) -> i64 {
self.intern.msecs()
}
pub fn csecs(&self) -> i64 {
self.intern.msecs()
}
pub fn secs(&self) -> i64 {
self.intern.msecs()
}
pub fn mins(&self) -> i64 {
self.intern.msecs()
}
pub fn hours(&self) -> i64 {
self.intern.hours()
}
pub fn msecs_comp(&self) -> i64 {
self.intern.msecs_comp()
}
pub fn csecs_comp(&self) -> i64 {
self.intern.csecs_comp()
}
pub fn secs_comp(&self) -> i64 {
self.intern.secs_comp()
}
pub fn mins_comp(&self) -> i64 {
self.intern.mins_comp()
}
pub fn is_negative(&self) -> bool {
self.intern.is_negative()
}
}
impl Neg for $i {
type Output = $i;
fn neg(self) -> $i {
$i::new(-self.intern)
}
}
impl Display for $i {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(f, "{}", self.intern)
}
}
}
}
create_time_type!{TimePoint}
create_time_type!{TimeDelta}
macro_rules! impl_add {
($a:ty, $b:ty, $output:ident) => {
impl Add<$b> for $a {
type Output = $output;
fn add(self, rhs: $b) -> $output {
$output::new(self.intern + rhs.intern)
}
}
}
}
macro_rules! impl_sub {
($a:ty, $b:ty, $output:ident) => {
impl Sub<$b> for $a {
type Output = $output;
fn sub(self, rhs: $b) -> $output {
$output::new(self.intern - rhs.intern)
}
}
}
}
macro_rules! impl_add_assign {
($a:ty, $b:ty) => {
impl AddAssign<$b> for $a {
fn add_assign(&mut self, r: $b) {
self.intern += r.intern;
}
}
}
}
macro_rules! impl_sub_assign {
($a:ty, $b:ty) => {
impl SubAssign<$b> for $a {
fn sub_assign(&mut self, r: $b) {
self.intern -= r.intern;
}
}
}
}
impl_add!(TimeDelta, TimeDelta, TimeDelta);
impl_add!(TimePoint, TimeDelta, TimePoint);
impl_add!(TimeDelta, TimePoint, TimePoint);
impl_sub!(TimeDelta, TimeDelta, TimeDelta);
impl_sub!(TimePoint, TimePoint, TimeDelta);
impl_sub!(TimePoint, TimeDelta, TimePoint);
impl_sub!(TimeDelta, TimePoint, TimePoint);
impl_add_assign!(TimeDelta, TimeDelta);
impl_add_assign!(TimePoint, TimeDelta);
impl_sub_assign!(TimeDelta, TimeDelta);
impl_sub_assign!(TimePoint, TimeDelta);
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TimeSpan {
pub start: TimePoint,
pub end: TimePoint,
}
impl TimeSpan {
pub fn new(start: TimePoint, end: TimePoint) -> TimeSpan {
TimeSpan {
start: start,
end: end,
}
}
pub fn len(&self) -> TimeDelta {
self.end - self.start
}
}
impl Add<TimeDelta> for TimeSpan {
type Output = TimeSpan;
fn add(self, rhs: TimeDelta) -> TimeSpan {
TimeSpan::new(self.start + rhs, self.end + rhs)
}
}
impl Sub<TimeDelta> for TimeSpan {
type Output = TimeSpan;
fn sub(self, rhs: TimeDelta) -> TimeSpan {
TimeSpan::new(self.start - rhs, self.end - rhs)
}
}
impl AddAssign<TimeDelta> for TimeSpan {
fn add_assign(&mut self, r: TimeDelta) {
self.start += r;
self.end += r;
}
}
impl SubAssign<TimeDelta> for TimeSpan {
fn sub_assign(&mut self, r: TimeDelta) {
self.start -= r;
self.end -= r;
}
}
#[cfg(test)]
mod tests {
#[test]
fn test_timing_display() {
let t = -super::Timing::from_components(12, 59, 29, 450);
assert_eq!(t.to_string(), "-12:59:29.450".to_string());
let t = super::Timing::from_msecs(0);
assert_eq!(t.to_string(), "0:00:00.000".to_string());
}
}