Skip to main content

proto_types/duration/
duration_impls.rs

1use crate::Duration;
2
3impl core::cmp::PartialOrd for Duration {
4	#[inline]
5	fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
6		Some(self.cmp(other))
7	}
8}
9
10impl core::cmp::Ord for Duration {
11	#[inline]
12	fn cmp(&self, other: &Self) -> core::cmp::Ordering {
13		self.total_nanos().cmp(&other.total_nanos())
14	}
15}
16
17#[cfg(feature = "serde")]
18mod serde {
19	use core::fmt;
20
21	use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
22
23	use crate::{Duration, ToString, format};
24
25	impl Serialize for Duration {
26		fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
27		where
28			S: Serializer,
29		{
30			let self_normalized = self.normalized();
31
32			let seconds = self_normalized.seconds;
33			let nanos = self_normalized.nanos;
34
35			let formatted_string = if nanos == 0 {
36				// If nanos are zero, just "Xs"
37				format!("{seconds}s")
38			} else {
39				let fractional_seconds_str = format!("{nanos:09}");
40
41				let trimmed_fractional_seconds = fractional_seconds_str.trim_end_matches('0');
42
43				format!("{seconds}.{trimmed_fractional_seconds}s")
44			};
45
46			serializer.serialize_str(&formatted_string)
47		}
48	}
49
50	impl<'de> Deserialize<'de> for Duration {
51		fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
52		where
53			D: Deserializer<'de>,
54		{
55			struct DurationVisitor;
56
57			impl de::Visitor<'_> for DurationVisitor {
58				type Value = Duration;
59
60				fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
61					formatter.write_str("A duration ending in 's'")
62				}
63
64				fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
65				where
66					E: de::Error,
67				{
68					if !value.ends_with('s') {
69						return Err(de::Error::custom("Duration should end with 's'"));
70					}
71
72					let duration_str = &value[..value.len() - 1]; // Remove 's' from the end
73
74					let mut parts = duration_str.split('.'); // Split seconds and fractional seconds
75
76					let seconds: i64 = parts
77						.next()
78						.ok_or_else(|| de::Error::custom("Missing seconds"))?
79						.parse()
80						.map_err(de::Error::custom)?;
81
82					let nanos: i32 = match parts.next() {
83						Some(fraction) => {
84							let mut fraction_str = fraction.to_string(); // Need to own it for modification
85							// Pad fraction to 9 digits (nanoseconds)
86							if fraction_str.len() > 9 {
87								// Handle too many fractional digits
88								return Err(de::Error::custom(format!(
89									"Fractional part has more than 9 digits: {}",
90									fraction_str.len()
91								)));
92							}
93							fraction_str.reserve(9 - fraction_str.len()); // Pre-allocate to avoid reallocations
94							for _ in fraction_str.len()..9 {
95								fraction_str.push('0');
96							}
97
98							fraction_str.parse().map_err(de::Error::custom)?
99						}
100						None => 0,
101					};
102
103					let mut duration = Duration { seconds, nanos };
104					duration.normalize(); // Normalize after creation
105
106					Ok(duration)
107				}
108			}
109
110			deserializer.deserialize_str(DurationVisitor)
111		}
112	}
113}