1use serde::{Deserialize, Serialize, de};
21
22#[derive(Debug, Copy, Clone, Eq, PartialEq)]
23pub struct Duration {
24 months: Months,
25 days: Days,
26 millis: Millis,
27}
28
29#[derive(Debug, Copy, Clone, Eq, PartialEq)]
30pub struct Months(u32);
31
32impl Months {
33 pub fn new(months: u32) -> Self {
34 Self(months)
35 }
36
37 fn as_bytes(&self) -> [u8; 4] {
38 self.0.to_le_bytes()
39 }
40}
41
42impl From<Months> for u32 {
43 fn from(days: Months) -> Self {
44 days.0
45 }
46}
47
48impl From<[u8; 4]> for Months {
49 fn from(bytes: [u8; 4]) -> Self {
50 Self(u32::from_le_bytes(bytes))
51 }
52}
53
54#[derive(Debug, Copy, Clone, Eq, PartialEq)]
55pub struct Days(u32);
56
57impl Days {
58 pub fn new(days: u32) -> Self {
59 Self(days)
60 }
61
62 fn as_bytes(&self) -> [u8; 4] {
63 self.0.to_le_bytes()
64 }
65}
66
67impl From<Days> for u32 {
68 fn from(days: Days) -> Self {
69 days.0
70 }
71}
72
73impl From<[u8; 4]> for Days {
74 fn from(bytes: [u8; 4]) -> Self {
75 Self(u32::from_le_bytes(bytes))
76 }
77}
78
79#[derive(Debug, Copy, Clone, Eq, PartialEq)]
80pub struct Millis(u32);
81
82impl Millis {
83 pub fn new(millis: u32) -> Self {
84 Self(millis)
85 }
86
87 fn as_bytes(&self) -> [u8; 4] {
88 self.0.to_le_bytes()
89 }
90}
91
92impl From<Millis> for u32 {
93 fn from(days: Millis) -> Self {
94 days.0
95 }
96}
97
98impl From<[u8; 4]> for Millis {
99 fn from(bytes: [u8; 4]) -> Self {
100 Self(u32::from_le_bytes(bytes))
101 }
102}
103
104impl Duration {
105 pub fn new(months: Months, days: Days, millis: Millis) -> Self {
107 Self {
108 months,
109 days,
110 millis,
111 }
112 }
113
114 pub fn months(&self) -> Months {
116 self.months
117 }
118
119 pub fn days(&self) -> Days {
121 self.days
122 }
123
124 pub fn millis(&self) -> Millis {
126 self.millis
127 }
128}
129
130impl From<&Duration> for [u8; 12] {
131 fn from(duration: &Duration) -> Self {
132 let mut bytes = [0u8; 12];
133 bytes[0..4].copy_from_slice(&duration.months.as_bytes());
134 bytes[4..8].copy_from_slice(&duration.days.as_bytes());
135 bytes[8..12].copy_from_slice(&duration.millis.as_bytes());
136 bytes
137 }
138}
139
140impl From<Duration> for [u8; 12] {
141 fn from(duration: Duration) -> Self {
142 (&duration).into()
143 }
144}
145
146impl From<&[u8; 12]> for Duration {
147 fn from(bytes: &[u8; 12]) -> Self {
148 Self {
149 months: Months::from([bytes[0], bytes[1], bytes[2], bytes[3]]),
150 days: Days::from([bytes[4], bytes[5], bytes[6], bytes[7]]),
151 millis: Millis::from([bytes[8], bytes[9], bytes[10], bytes[11]]),
152 }
153 }
154}
155
156impl From<[u8; 12]> for Duration {
157 fn from(bytes: [u8; 12]) -> Duration {
158 (&bytes).into()
159 }
160}
161
162impl Serialize for Duration {
163 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
164 where
165 S: serde::Serializer,
166 {
167 let value_bytes: [u8; 12] = self.into();
168 serializer.serialize_bytes(&value_bytes)
169 }
170}
171
172impl<'de> Deserialize<'de> for Duration {
173 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
174 where
175 D: serde::Deserializer<'de>,
176 {
177 struct DurationVisitor;
178
179 impl de::Visitor<'_> for DurationVisitor {
180 type Value = Duration;
181
182 fn expecting(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
183 write!(f, "a byte array with size 12")
184 }
185
186 fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
187 where
188 E: de::Error,
189 {
190 if v.len() != 12 {
191 Err(E::custom(format!(
192 "Expected byte array of length 12, but length is {}",
193 v.len()
194 )))
195 } else {
196 let v_slice: [u8; 12] = v[..12].try_into().unwrap();
197 Ok(Duration::from(v_slice))
198 }
199 }
200 }
201
202 deserializer.deserialize_bytes(DurationVisitor)
203 }
204}
205
206#[cfg(test)]
207mod tests {
208 use super::*;
209 use crate::types::Value;
210 use apache_avro_test_helper::TestResult;
211
212 #[test]
213 fn avro_rs_382_duration_from_value() -> TestResult {
214 let val = Value::Duration(Duration::new(Months::new(7), Days::new(4), Millis::new(45)));
215 let de_val: Duration = crate::from_value(&val)?;
216 assert_eq!(de_val.months(), Months::new(7));
217 assert_eq!(de_val.days(), Days::new(4));
218 assert_eq!(de_val.millis(), Millis::new(45));
219 Ok(())
220 }
221
222 #[test]
223 fn avro_rs_382_duration_to_value() -> TestResult {
224 let duration = Duration::new(Months::new(7), Days::new(4), Millis::new(45));
225 let ser_val = crate::to_value(duration)?;
226 match ser_val {
227 Value::Bytes(b) => {
229 assert_eq!(b, vec![7, 0, 0, 0, 4, 0, 0, 0, 45, 0, 0, 0]);
230 }
231 _ => {
232 Err(format!("Expected a Bytes value but got {ser_val:?}"))?;
233 }
234 }
235 Ok(())
236 }
237}