use serde_derive::{Deserialize, Serialize};
use std::cmp;
use std::convert::TryInto;
use std::fmt::Formatter;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ops;
use std::time;
const BILLION: i64 = 1_000_000_000;
#[derive(Copy, Clone, Default, Serialize, Deserialize, Debug, Eq)]
pub struct Time {
pub sec: u32,
pub nsec: u32,
}
impl Hash for Time {
fn hash<H: Hasher>(&self, state: &mut H) {
self.nanos().hash(state)
}
}
impl Time {
#[inline]
pub fn new() -> Time {
Self::default()
}
#[inline]
pub fn from_nanos(t: i64) -> Time {
Time {
sec: (t / BILLION) as u32,
nsec: (t % BILLION) as u32,
}
}
#[inline]
pub fn from_seconds(sec: u32) -> Time {
Time { sec, nsec: 0 }
}
#[inline]
pub fn nanos(self) -> i64 {
i64::from(self.sec) * BILLION + i64::from(self.nsec)
}
#[inline]
pub fn seconds(self) -> f64 {
f64::from(self.sec) + f64::from(self.nsec) / BILLION as f64
}
}
fn display_nanos(nanos: &str, f: &mut Formatter<'_>) -> fmt::Result {
let split_point = nanos.len() - 9;
let characters = nanos.chars();
let (left, right) = characters.as_str().split_at(split_point);
write!(f, "{}.{}", left, right)
}
impl fmt::Display for Time {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
display_nanos(&format!("{:010}", self.nanos()), f)
}
}
impl cmp::PartialEq for Time {
fn eq(&self, other: &Self) -> bool {
self.nanos() == other.nanos()
}
}
impl cmp::PartialOrd for Time {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
self.nanos().partial_cmp(&other.nanos())
}
}
impl cmp::Ord for Time {
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.nanos().cmp(&other.nanos())
}
}
impl From<time::SystemTime> for Time {
fn from(other: time::SystemTime) -> Self {
let epoch = time::SystemTime::UNIX_EPOCH;
let elapsed = other.duration_since(epoch)
.expect("Dates before 1970 are not supported by the ROS time format");
let sec = elapsed.as_secs()
.try_into()
.expect("Dates after 2100 are not supported by the ROS time format");
Self {
sec,
nsec: elapsed.subsec_nanos(),
}
}
}
impl From<Time> for time::SystemTime {
fn from(other: Time) -> Self {
let elapsed = time::Duration::new(other.sec.into(), other.nsec);
time::SystemTime::UNIX_EPOCH + elapsed
}
}
#[derive(Copy, Clone, Default, Serialize, Deserialize, Debug, Eq)]
pub struct Duration {
pub sec: i32,
pub nsec: i32,
}
impl Hash for Duration {
fn hash<H: Hasher>(&self, state: &mut H) {
self.nanos().hash(state)
}
}
impl fmt::Display for Duration {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let data = self.nanos();
display_nanos(
&format!(
"{}{:010}",
if data.is_negative() { "-" } else { "" },
data.abs()
),
f,
)
}
}
impl Duration {
#[inline]
pub fn new() -> Duration {
Self::default()
}
#[inline]
pub fn from_nanos(t: i64) -> Duration {
Duration {
sec: (t / BILLION) as i32,
nsec: (t % BILLION) as i32,
}
}
#[inline]
pub fn from_seconds(sec: i32) -> Duration {
Duration { sec, nsec: 0 }
}
#[inline]
pub fn nanos(self) -> i64 {
i64::from(self.sec) * BILLION + i64::from(self.nsec)
}
#[inline]
pub fn seconds(self) -> f64 {
f64::from(self.sec) + f64::from(self.nsec) / BILLION as f64
}
}
impl cmp::PartialEq for Duration {
fn eq(&self, other: &Self) -> bool {
self.nanos() == other.nanos()
}
}
impl cmp::PartialOrd for Duration {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
self.nanos().partial_cmp(&other.nanos())
}
}
impl cmp::Ord for Duration {
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.nanos().cmp(&other.nanos())
}
}
impl ops::Add<Duration> for Time {
type Output = Time;
fn add(self, rhs: Duration) -> Self::Output {
Time::from_nanos(self.nanos() + rhs.nanos())
}
}
impl ops::Add<Duration> for Duration {
type Output = Duration;
fn add(self, rhs: Duration) -> Self::Output {
Duration::from_nanos(self.nanos() + rhs.nanos())
}
}
impl ops::Sub<Time> for Time {
type Output = Duration;
fn sub(self, rhs: Time) -> Self::Output {
Duration::from_nanos(self.nanos() - rhs.nanos())
}
}
impl ops::Sub<Duration> for Time {
type Output = Time;
fn sub(self, rhs: Duration) -> Self::Output {
Time::from_nanos(self.nanos() - rhs.nanos())
}
}
impl ops::Sub<Duration> for Duration {
type Output = Duration;
fn sub(self, rhs: Duration) -> Self::Output {
Duration::from_nanos(self.nanos() - rhs.nanos())
}
}
impl ops::Neg for Duration {
type Output = Duration;
fn neg(self) -> Self::Output {
Duration {
sec: -self.sec,
nsec: -self.nsec,
}
}
}
impl From<time::Duration> for Duration {
fn from(std_duration: time::Duration) -> Self {
let sec = std_duration.as_secs()
.try_into()
.expect("Durations longer than 68 years are not supported by the ROS time format");
Duration {
sec,
nsec: std_duration.subsec_nanos() as i32,
}
}
}
impl From<Duration> for time::Duration {
fn from(other: Duration) -> Self {
let mut extra_sec = other.nsec / 1_000_000_000;
let mut nsec = other.nsec % 1_000_000_000;
if nsec < 0 {
extra_sec -= 1;
nsec += 1_000_000_000;
}
Self::new(
(other.sec + extra_sec).try_into().unwrap(),
nsec as u32,
)
}
}