use bytecodec::{ErrorKind, Result};
use std;
use std::time::Duration;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Timestamp(i32);
impl Timestamp {
pub fn new(milliseconds: i32) -> Self {
Timestamp(milliseconds)
}
pub fn value(self) -> i32 {
self.0
}
pub fn to_duration(self) -> Option<Duration> {
if self.0 >= 0 {
Some(Duration::from_millis(self.0 as u64))
} else {
None
}
}
pub fn from_duration(duration: Duration) -> Result<Self> {
let milliseconds = duration.as_secs() * 1000 + u64::from(duration.subsec_millis());
track_assert!(
milliseconds <= std::i32::MAX as u64,
ErrorKind::InvalidInput;
duration
);
Ok(Timestamp(milliseconds as i32))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct TimeOffset(i32);
impl TimeOffset {
pub fn new(offset: i32) -> Result<Self> {
track_assert_eq!(((offset << 8) >> 8), offset, ErrorKind::InvalidInput);
Ok(TimeOffset(offset))
}
pub fn value(self) -> i32 {
self.0
}
pub(crate) fn from_u24(n: u32) -> Self {
TimeOffset(((n << 8) as i32) >> 8)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn timestamp_works() {
let t = Timestamp::new(123);
assert_eq!(t.value(), 123);
assert_eq!(t.to_duration(), Some(Duration::from_millis(123)));
assert_eq!(
Some(t),
Timestamp::from_duration(Duration::from_millis(123)).ok()
);
let t = Timestamp::new(-123);
assert_eq!(t.value(), -123);
assert_eq!(t.to_duration(), None);
assert_eq!(
None,
Timestamp::from_duration(Duration::from_secs(0xFFFF_FFFF)).ok()
);
}
#[test]
fn time_offset_works() {
assert_eq!(TimeOffset::new(123).map(|t| t.value()).ok(), Some(123));
assert_eq!(TimeOffset::new(-12).map(|t| t.value()).ok(), Some(-12));
assert!(TimeOffset::new(0x0080_0000).is_err());
assert!(TimeOffset::new(0x0080_0000 - 1).is_ok());
assert!(TimeOffset::new(-0x0080_0000).is_ok());
assert!(TimeOffset::new(-0x0080_0000 - 1).is_err());
}
}