1use std::ptr;
5
6use reifydb_value::{
7 reifydb_assertions,
8 value::{duration::Duration, value_type::ValueType},
9};
10
11use crate::encoded::{row::EncodedRow, shape::RowShape};
12
13impl RowShape {
14 pub fn set_duration(&self, row: &mut EncodedRow, index: usize, value: Duration) {
15 let field = &self.fields()[index];
16 reifydb_assertions! {
17 assert!(
18 row.len() >= self.total_static_size(),
19 "row/shape size mismatch: row.len()={} < total_static_size()={}",
20 row.len(),
21 self.total_static_size()
22 );
23 assert_eq!(*field.constraint.get_type().inner_type(), ValueType::Duration);
24 }
25 row.set_valid(index, true);
26
27 let months = value.get_months();
28 let days = value.get_days();
29 let nanos = value.get_nanos();
30 unsafe {
31 ptr::write_unaligned(
32 row.make_mut().as_mut_ptr().add(field.offset as usize) as *mut i32,
33 months,
34 );
35
36 ptr::write_unaligned(
37 row.make_mut().as_mut_ptr().add(field.offset as usize + 4) as *mut i32,
38 days,
39 );
40
41 ptr::write_unaligned(
42 row.make_mut().as_mut_ptr().add(field.offset as usize + 8) as *mut i64,
43 nanos,
44 );
45 }
46 }
47
48 pub fn get_duration(&self, row: &EncodedRow, index: usize) -> Duration {
49 let field = &self.fields()[index];
50 reifydb_assertions! {
51 assert!(
52 row.len() >= self.total_static_size(),
53 "row/shape size mismatch: row.len()={} < total_static_size()={}",
54 row.len(),
55 self.total_static_size()
56 );
57 assert_eq!(*field.constraint.get_type().inner_type(), ValueType::Duration);
58 }
59 unsafe {
60 let months = (row.as_ptr().add(field.offset as usize) as *const i32).read_unaligned();
61
62 let days = (row.as_ptr().add(field.offset as usize + 4) as *const i32).read_unaligned();
63
64 let nanos = (row.as_ptr().add(field.offset as usize + 8) as *const i64).read_unaligned();
65 Duration::new(months, days, nanos).expect("stored duration must be valid")
66 }
67 }
68
69 pub fn try_get_duration(&self, row: &EncodedRow, index: usize) -> Option<Duration> {
70 if row.is_defined(index) && self.fields()[index].constraint.get_type() == ValueType::Duration {
71 Some(self.get_duration(row, index))
72 } else {
73 None
74 }
75 }
76}
77
78#[cfg(test)]
79pub mod tests {
80 use reifydb_value::value::{duration::Duration, value_type::ValueType};
81
82 use crate::encoded::shape::RowShape;
83
84 #[test]
85 fn test_set_get_duration() {
86 let shape = RowShape::testing(&[ValueType::Duration]);
87 let mut row = shape.allocate();
88
89 let value = Duration::from_seconds(-7200).unwrap();
90 shape.set_duration(&mut row, 0, value.clone());
91 assert_eq!(shape.get_duration(&row, 0), value);
92 }
93
94 #[test]
95 fn test_try_get_duration() {
96 let shape = RowShape::testing(&[ValueType::Duration]);
97 let mut row = shape.allocate();
98
99 assert_eq!(shape.try_get_duration(&row, 0), None);
100
101 let test_duration = Duration::from_days(30).unwrap();
102 shape.set_duration(&mut row, 0, test_duration.clone());
103 assert_eq!(shape.try_get_duration(&row, 0), Some(test_duration));
104 }
105
106 #[test]
107 fn test_zero() {
108 let shape = RowShape::testing(&[ValueType::Duration]);
109 let mut row = shape.allocate();
110
111 let zero = Duration::default(); shape.set_duration(&mut row, 0, zero.clone());
113 assert_eq!(shape.get_duration(&row, 0), zero);
114 }
115
116 #[test]
117 fn test_various_durations() {
118 let shape = RowShape::testing(&[ValueType::Duration]);
119
120 let test_durations = [
121 Duration::from_seconds(0).unwrap(), Duration::from_seconds(60).unwrap(), Duration::from_seconds(3600).unwrap(), Duration::from_seconds(86400).unwrap(), Duration::from_days(7).unwrap(), Duration::from_days(30).unwrap(), Duration::from_weeks(52).unwrap(), ];
129
130 for duration in test_durations {
131 let mut row = shape.allocate();
132 shape.set_duration(&mut row, 0, duration.clone());
133 assert_eq!(shape.get_duration(&row, 0), duration);
134 }
135 }
136
137 #[test]
138 fn test_negative_durations() {
139 let shape = RowShape::testing(&[ValueType::Duration]);
140
141 let negative_durations = [
142 Duration::from_seconds(-60).unwrap(), Duration::from_seconds(-3600).unwrap(), Duration::from_seconds(-86400).unwrap(), Duration::from_days(-7).unwrap(), Duration::from_weeks(-4).unwrap(), ];
148
149 for duration in negative_durations {
150 let mut row = shape.allocate();
151 shape.set_duration(&mut row, 0, duration.clone());
152 assert_eq!(shape.get_duration(&row, 0), duration);
153 }
154 }
155
156 #[test]
157 fn test_complex_parts() {
158 let shape = RowShape::testing(&[ValueType::Duration]);
159 let mut row = shape.allocate();
160
161 let complex_duration = Duration::new(
163 6, 15, 123456789, )
167 .unwrap();
168 shape.set_duration(&mut row, 0, complex_duration.clone());
169 assert_eq!(shape.get_duration(&row, 0), complex_duration);
170 }
171
172 #[test]
173 fn test_mixed_with_other_types() {
174 let shape = RowShape::testing(&[
175 ValueType::Duration,
176 ValueType::Boolean,
177 ValueType::Duration,
178 ValueType::Int8,
179 ]);
180 let mut row = shape.allocate();
181
182 let duration1 = Duration::from_hours(24).unwrap();
183 let duration2 = Duration::from_minutes(-30).unwrap();
184
185 shape.set_duration(&mut row, 0, duration1.clone());
186 shape.set_bool(&mut row, 1, true);
187 shape.set_duration(&mut row, 2, duration2.clone());
188 shape.set_i64(&mut row, 3, 987654321);
189
190 assert_eq!(shape.get_duration(&row, 0), duration1);
191 assert_eq!(shape.get_bool(&row, 1), true);
192 assert_eq!(shape.get_duration(&row, 2), duration2);
193 assert_eq!(shape.get_i64(&row, 3), 987654321);
194 }
195
196 #[test]
197 fn test_undefined_handling() {
198 let shape = RowShape::testing(&[ValueType::Duration, ValueType::Duration]);
199 let mut row = shape.allocate();
200
201 let duration = Duration::from_days(100).unwrap();
202 shape.set_duration(&mut row, 0, duration.clone());
203
204 assert_eq!(shape.try_get_duration(&row, 0), Some(duration));
205 assert_eq!(shape.try_get_duration(&row, 1), None);
206
207 shape.set_none(&mut row, 0);
208 assert_eq!(shape.try_get_duration(&row, 0), None);
209 }
210
211 #[test]
212 fn test_large_values() {
213 let shape = RowShape::testing(&[ValueType::Duration]);
214 let mut row = shape.allocate();
215
216 let large_duration = Duration::new(
218 120, 3650, 123456789012345, )
222 .unwrap();
223 shape.set_duration(&mut row, 0, large_duration.clone());
224 assert_eq!(shape.get_duration(&row, 0), large_duration);
225 }
226
227 #[test]
228 fn test_precision_preservation() {
229 let shape = RowShape::testing(&[ValueType::Duration]);
230 let mut row = shape.allocate();
231
232 let precise_duration = Duration::new(
234 5, 20, 999999999, )
238 .unwrap();
239 shape.set_duration(&mut row, 0, precise_duration.clone());
240
241 let retrieved = shape.get_duration(&row, 0);
242 assert_eq!(retrieved, precise_duration);
243
244 let orig_months = precise_duration.get_months();
245 let orig_days = precise_duration.get_days();
246 let orig_nanos = precise_duration.get_nanos();
247 let ret_months = retrieved.get_months();
248 let ret_days = retrieved.get_days();
249 let ret_nanos = retrieved.get_nanos();
250 assert_eq!(orig_months, ret_months);
251 assert_eq!(orig_days, ret_days);
252 assert_eq!(orig_nanos, ret_nanos);
253 }
254
255 #[test]
256 fn test_common_durations() {
257 let shape = RowShape::testing(&[ValueType::Duration]);
258
259 let common_durations = [
261 Duration::from_seconds(1).unwrap(), Duration::from_seconds(30).unwrap(), Duration::from_minutes(5).unwrap(), Duration::from_minutes(15).unwrap(), Duration::from_hours(1).unwrap(), Duration::from_hours(8).unwrap(), Duration::from_days(1).unwrap(), Duration::from_weeks(1).unwrap(), Duration::from_weeks(2).unwrap(), ];
271
272 for duration in common_durations {
273 let mut row = shape.allocate();
274 shape.set_duration(&mut row, 0, duration.clone());
275 assert_eq!(shape.get_duration(&row, 0), duration);
276 }
277 }
278
279 #[test]
280 fn test_boundary_values() {
281 let shape = RowShape::testing(&[ValueType::Duration]);
282
283 let boundary_durations = [
285 Duration::new(i32::MAX, 0, 0).unwrap(), Duration::new(i32::MIN, 0, 0).unwrap(), Duration::new(0, i32::MAX, 0).unwrap(), Duration::new(0, i32::MIN, 0).unwrap(), Duration::new(0, 0, i64::MAX).unwrap(), Duration::new(0, 0, i64::MIN).unwrap(), ];
292
293 for duration in boundary_durations {
294 let mut row = shape.allocate();
295 shape.set_duration(&mut row, 0, duration.clone());
296 assert_eq!(shape.get_duration(&row, 0), duration);
297 }
298 }
299
300 #[test]
301 fn test_try_get_duration_wrong_type() {
302 let shape = RowShape::testing(&[ValueType::Boolean]);
303 let mut row = shape.allocate();
304
305 shape.set_bool(&mut row, 0, true);
306
307 assert_eq!(shape.try_get_duration(&row, 0), None);
308 }
309}