1use std::ptr;
5
6use reifydb_type::value::{duration::Duration, r#type::Type};
7
8use crate::encoded::{row::EncodedRow, shape::RowShape};
9
10impl RowShape {
11 pub fn set_duration(&self, row: &mut EncodedRow, index: usize, value: Duration) {
12 let field = &self.fields()[index];
13 debug_assert!(row.len() >= self.total_static_size());
14 debug_assert_eq!(*field.constraint.get_type().inner_type(), Type::Duration);
15 row.set_valid(index, true);
16
17 let months = value.get_months();
18 let days = value.get_days();
19 let nanos = value.get_nanos();
20 unsafe {
21 ptr::write_unaligned(
22 row.make_mut().as_mut_ptr().add(field.offset as usize) as *mut i32,
23 months,
24 );
25
26 ptr::write_unaligned(
27 row.make_mut().as_mut_ptr().add(field.offset as usize + 4) as *mut i32,
28 days,
29 );
30
31 ptr::write_unaligned(
32 row.make_mut().as_mut_ptr().add(field.offset as usize + 8) as *mut i64,
33 nanos,
34 );
35 }
36 }
37
38 pub fn get_duration(&self, row: &EncodedRow, index: usize) -> Duration {
39 let field = &self.fields()[index];
40 debug_assert!(row.len() >= self.total_static_size());
41 debug_assert_eq!(*field.constraint.get_type().inner_type(), Type::Duration);
42 unsafe {
43 let months = (row.as_ptr().add(field.offset as usize) as *const i32).read_unaligned();
44
45 let days = (row.as_ptr().add(field.offset as usize + 4) as *const i32).read_unaligned();
46
47 let nanos = (row.as_ptr().add(field.offset as usize + 8) as *const i64).read_unaligned();
48 Duration::new(months, days, nanos).expect("stored duration must be valid")
49 }
50 }
51
52 pub fn try_get_duration(&self, row: &EncodedRow, index: usize) -> Option<Duration> {
53 if row.is_defined(index) && self.fields()[index].constraint.get_type() == Type::Duration {
54 Some(self.get_duration(row, index))
55 } else {
56 None
57 }
58 }
59}
60
61#[cfg(test)]
62pub mod tests {
63 use reifydb_type::value::{duration::Duration, r#type::Type};
64
65 use crate::encoded::shape::RowShape;
66
67 #[test]
68 fn test_set_get_duration() {
69 let shape = RowShape::testing(&[Type::Duration]);
70 let mut row = shape.allocate();
71
72 let value = Duration::from_seconds(-7200).unwrap();
73 shape.set_duration(&mut row, 0, value.clone());
74 assert_eq!(shape.get_duration(&row, 0), value);
75 }
76
77 #[test]
78 fn test_try_get_duration() {
79 let shape = RowShape::testing(&[Type::Duration]);
80 let mut row = shape.allocate();
81
82 assert_eq!(shape.try_get_duration(&row, 0), None);
83
84 let test_duration = Duration::from_days(30).unwrap();
85 shape.set_duration(&mut row, 0, test_duration.clone());
86 assert_eq!(shape.try_get_duration(&row, 0), Some(test_duration));
87 }
88
89 #[test]
90 fn test_zero() {
91 let shape = RowShape::testing(&[Type::Duration]);
92 let mut row = shape.allocate();
93
94 let zero = Duration::default(); shape.set_duration(&mut row, 0, zero.clone());
96 assert_eq!(shape.get_duration(&row, 0), zero);
97 }
98
99 #[test]
100 fn test_various_durations() {
101 let shape = RowShape::testing(&[Type::Duration]);
102
103 let test_durations = [
104 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(), ];
112
113 for duration in test_durations {
114 let mut row = shape.allocate();
115 shape.set_duration(&mut row, 0, duration.clone());
116 assert_eq!(shape.get_duration(&row, 0), duration);
117 }
118 }
119
120 #[test]
121 fn test_negative_durations() {
122 let shape = RowShape::testing(&[Type::Duration]);
123
124 let negative_durations = [
125 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(), ];
131
132 for duration in negative_durations {
133 let mut row = shape.allocate();
134 shape.set_duration(&mut row, 0, duration.clone());
135 assert_eq!(shape.get_duration(&row, 0), duration);
136 }
137 }
138
139 #[test]
140 fn test_complex_parts() {
141 let shape = RowShape::testing(&[Type::Duration]);
142 let mut row = shape.allocate();
143
144 let complex_duration = Duration::new(
146 6, 15, 123456789, )
150 .unwrap();
151 shape.set_duration(&mut row, 0, complex_duration.clone());
152 assert_eq!(shape.get_duration(&row, 0), complex_duration);
153 }
154
155 #[test]
156 fn test_mixed_with_other_types() {
157 let shape = RowShape::testing(&[Type::Duration, Type::Boolean, Type::Duration, Type::Int8]);
158 let mut row = shape.allocate();
159
160 let duration1 = Duration::from_hours(24).unwrap();
161 let duration2 = Duration::from_minutes(-30).unwrap();
162
163 shape.set_duration(&mut row, 0, duration1.clone());
164 shape.set_bool(&mut row, 1, true);
165 shape.set_duration(&mut row, 2, duration2.clone());
166 shape.set_i64(&mut row, 3, 987654321);
167
168 assert_eq!(shape.get_duration(&row, 0), duration1);
169 assert_eq!(shape.get_bool(&row, 1), true);
170 assert_eq!(shape.get_duration(&row, 2), duration2);
171 assert_eq!(shape.get_i64(&row, 3), 987654321);
172 }
173
174 #[test]
175 fn test_undefined_handling() {
176 let shape = RowShape::testing(&[Type::Duration, Type::Duration]);
177 let mut row = shape.allocate();
178
179 let duration = Duration::from_days(100).unwrap();
180 shape.set_duration(&mut row, 0, duration.clone());
181
182 assert_eq!(shape.try_get_duration(&row, 0), Some(duration));
183 assert_eq!(shape.try_get_duration(&row, 1), None);
184
185 shape.set_none(&mut row, 0);
186 assert_eq!(shape.try_get_duration(&row, 0), None);
187 }
188
189 #[test]
190 fn test_large_values() {
191 let shape = RowShape::testing(&[Type::Duration]);
192 let mut row = shape.allocate();
193
194 let large_duration = Duration::new(
196 120, 3650, 123456789012345, )
200 .unwrap();
201 shape.set_duration(&mut row, 0, large_duration.clone());
202 assert_eq!(shape.get_duration(&row, 0), large_duration);
203 }
204
205 #[test]
206 fn test_precision_preservation() {
207 let shape = RowShape::testing(&[Type::Duration]);
208 let mut row = shape.allocate();
209
210 let precise_duration = Duration::new(
212 5, 20, 999999999, )
216 .unwrap();
217 shape.set_duration(&mut row, 0, precise_duration.clone());
218
219 let retrieved = shape.get_duration(&row, 0);
220 assert_eq!(retrieved, precise_duration);
221
222 let orig_months = precise_duration.get_months();
223 let orig_days = precise_duration.get_days();
224 let orig_nanos = precise_duration.get_nanos();
225 let ret_months = retrieved.get_months();
226 let ret_days = retrieved.get_days();
227 let ret_nanos = retrieved.get_nanos();
228 assert_eq!(orig_months, ret_months);
229 assert_eq!(orig_days, ret_days);
230 assert_eq!(orig_nanos, ret_nanos);
231 }
232
233 #[test]
234 fn test_common_durations() {
235 let shape = RowShape::testing(&[Type::Duration]);
236
237 let common_durations = [
239 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(), ];
249
250 for duration in common_durations {
251 let mut row = shape.allocate();
252 shape.set_duration(&mut row, 0, duration.clone());
253 assert_eq!(shape.get_duration(&row, 0), duration);
254 }
255 }
256
257 #[test]
258 fn test_boundary_values() {
259 let shape = RowShape::testing(&[Type::Duration]);
260
261 let boundary_durations = [
263 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(), ];
270
271 for duration in boundary_durations {
272 let mut row = shape.allocate();
273 shape.set_duration(&mut row, 0, duration.clone());
274 assert_eq!(shape.get_duration(&row, 0), duration);
275 }
276 }
277
278 #[test]
279 fn test_try_get_duration_wrong_type() {
280 let shape = RowShape::testing(&[Type::Boolean]);
281 let mut row = shape.allocate();
282
283 shape.set_bool(&mut row, 0, true);
284
285 assert_eq!(shape.try_get_duration(&row, 0), None);
286 }
287}