1use core::str::FromStr;
4
5use derive_more::{Debug, Display};
6#[cfg(feature = "zerocopy-08")]
7use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
8
9use crate::{ParseTimedeltaError, Timedelta};
10
11#[repr(transparent)]
29#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
30#[display("{}", Timedelta(*_0))]
31#[debug("{self}")]
32#[cfg_attr(feature = "zerocopy-08", derive(FromBytes, IntoBytes, Immutable, KnownLayout))]
33pub struct Uptime(pub(crate) i64);
34
35#[repr(transparent)]
50#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
51#[display("{}", Timedelta(*_0))]
52#[debug("{self}")]
53#[cfg_attr(feature = "zerocopy-08", derive(FromBytes, IntoBytes, Immutable, KnownLayout))]
54pub struct RawUptime(pub(crate) i64);
55
56#[repr(transparent)]
69#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
70#[display("{}", Timedelta(*_0))]
71#[debug("{self}")]
72#[cfg_attr(feature = "zerocopy-08", derive(FromBytes, IntoBytes, Immutable, KnownLayout))]
73pub struct BootUptime(pub(crate) i64);
74
75macro_rules! read_as_span {
77 ($point:ident) => {
78 impl FromStr for $point {
80 type Err = ParseTimedeltaError;
81
82 fn from_str(text: &str) -> Result<Self, Self::Err> {
83 text.parse().map(|span: Timedelta| Self(span.0))
84 }
85 }
86 };
87}
88
89read_as_span!(Uptime);
90read_as_span!(RawUptime);
91read_as_span!(BootUptime);
92
93#[cfg(test)]
94mod tests {
95 use alloc::format;
96 use alloc::string::ToString as _;
97
98 use crate::{BootUptime, ParseTimedeltaError, RawUptime, Uptime};
99
100 #[test]
101 fn a_point_from_boot_reads_back_from_its_span() {
102 let uptime = Uptime::from_millis(90_250);
103 assert_eq!(uptime.to_string(), "1m30s250ms", "written as the span since the origin");
104 assert_eq!("1m30s250ms".parse(), Ok(uptime), "and read back");
105 assert_eq!("2h".parse(), Ok(BootUptime::from_secs(7_200)), "on every clock from boot");
106 assert_eq!("-".parse::<RawUptime>(), Err(ParseTimedeltaError), "refused as a span is");
107 }
108
109 #[test]
110 fn a_width_pads_a_point_from_boot_as_it_pads_a_span() {
111 assert_eq!(format!("[{:>8}]", Uptime::from_millis(500)), "[ 500ms]", "padded");
112 assert_eq!(format!("{:?}", RawUptime::from_secs(2)), "2s", "and debugged as written");
113 }
114}