proto_types/duration/
duration_impls.rs

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