use serde::{Deserialize, Serialize};
use log::{error, warn};
use crate::{message::Message, ros_time::ROSTime};
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
#[serde(from = "repr::Time", into = "repr::Time")]
pub struct Time {
nanos_since_epoch: i64,
}
impl Time {
pub const ZERO: Time = Time {
nanos_since_epoch: 0,
};
pub const DUMMY: Time = Time {
nanos_since_epoch: 1234567890123,
};
pub(crate) fn now() -> Self {
chrono::Utc::now()
.timestamp_nanos_opt()
.map(Self::from_nanos)
.unwrap_or_else(|| {
error!("Timestamp out of range.");
Time::ZERO })
}
pub fn from_nanos(nanos_since_epoch: i64) -> Self {
Self { nanos_since_epoch }
}
pub fn to_nanos(&self) -> i64 {
self.nanos_since_epoch
}
}
impl From<repr::Time> for Time {
fn from(rt: repr::Time) -> Time {
if rt.nanosec >= 1_000_000_000 {
warn!(
"builtin_interfaces::Time fractional part at 1 or greater: {} / 10^9 ",
rt.nanosec
);
}
Time::from_nanos((rt.sec as i64) * 1_000_000_000 + (rt.nanosec as i64))
}
}
impl From<Time> for repr::Time {
fn from(t: Time) -> repr::Time {
let t = t.to_nanos();
let quot = t / 1_000_000_000;
let rem = t % 1_000_000_000;
if rem >= 0 {
repr::Time {
sec: if quot > (i32::MAX as i64) {
warn!("rcl_interfaces::Time conversion overflow");
i32::MAX
} else if quot < (i32::MIN as i64) {
warn!("rcl_interfaces::Time conversion underflow");
i32::MIN
} else {
quot as i32
},
nanosec: rem as u32,
}
} else {
let quot_sat = if quot >= (i32::MIN as i64) {
quot as i32
} else {
warn!("rcl_interfaces::Time conversion underflow");
i32::MIN
};
repr::Time {
sec: quot_sat - 1, nanosec: (1_000_000_000 + rem) as u32,
}
}
}
}
mod repr {
use serde::{Deserialize, Serialize};
use crate::message::Message;
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
pub struct Time {
pub sec: i32,
pub nanosec: u32,
}
impl Message for Time {}
}
impl From<ROSTime> for Time {
fn from(rt: ROSTime) -> Time {
Time::from_nanos(rt.to_nanos())
}
}
impl From<Time> for ROSTime {
fn from(t: Time) -> ROSTime {
ROSTime::from_nanos(t.to_nanos())
}
}
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct Duration {
sec: i32, nanosec: u32,
}
impl Message for Duration {}
impl Duration {
pub const fn zero() -> Self {
Self { sec: 0, nanosec: 0 }
}
pub const fn from_secs(sec: i32) -> Self {
Self { sec, nanosec: 0 }
}
pub const fn from_millis(millis: i64) -> Self {
let nanos = millis * 1_000_000; Self::from_nanos(nanos)
}
pub const fn from_nanos(nanos: i64) -> Self {
let quot = nanos / 1_000_000_000;
let rem = nanos % 1_000_000_000;
if rem >= 0 {
if quot > (i32::MAX as i64) {
Duration {
sec: i32::MAX,
nanosec: u32::MAX,
}
} else if quot <= (i32::MIN as i64) {
Duration {
sec: i32::MIN,
nanosec: 0,
}
} else {
Duration {
sec: quot as i32,
nanosec: rem as u32,
}
}
} else {
if quot <= (i32::MIN as i64) {
Duration {
sec: i32::MIN,
nanosec: 0,
}
} else {
Duration {
sec: (quot + 1) as i32,
nanosec: (1_000_000_000 + rem) as u32,
}
}
}
}
pub fn to_nanos(&self) -> i64 {
let s = self.sec as i64;
let ns = self.nanosec as i64;
1_000_000_000 * s + ns
}
}
#[cfg(test)]
mod test {
use super::{repr, Time};
fn repr_conv_test(t: Time) {
let rt: repr::Time = t.into();
println!("{rt:?}");
assert_eq!(t, Time::from(rt))
}
#[test]
fn repr_conversion() {
repr_conv_test(Time::from_nanos(999_999_999));
repr_conv_test(Time::from_nanos(1_000_000_000));
repr_conv_test(Time::from_nanos(1_000_000_001));
repr_conv_test(Time::from_nanos(1_999_999_999));
repr_conv_test(Time::from_nanos(2_000_000_000));
repr_conv_test(Time::from_nanos(2_000_000_001));
repr_conv_test(Time::from_nanos(-999_999_999));
repr_conv_test(Time::from_nanos(-1_000_000_000));
repr_conv_test(Time::from_nanos(-1_000_000_001));
repr_conv_test(Time::from_nanos(-1_999_999_999));
repr_conv_test(Time::from_nanos(-2_000_000_000));
repr_conv_test(Time::from_nanos(-2_000_000_001));
repr_conv_test(Time::from_nanos(0));
repr_conv_test(Time::from_nanos(1));
repr_conv_test(Time::from_nanos(-1));
}
}