Skip to main content

reifydb_codec/encoded/
time.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4use std::ptr;
5
6use reifydb_value::{
7	reifydb_assertions,
8	value::{time::Time, value_type::ValueType},
9};
10
11use crate::encoded::{row::EncodedRow, shape::RowShape};
12
13impl RowShape {
14	pub fn set_time(&self, row: &mut EncodedRow, index: usize, value: Time) {
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::Time);
24		}
25		row.set_valid(index, true);
26		unsafe {
27			ptr::write_unaligned(
28				row.make_mut().as_mut_ptr().add(field.offset as usize) as *mut u64,
29				value.to_nanos_since_midnight(),
30			)
31		}
32	}
33
34	pub fn get_time(&self, row: &EncodedRow, index: usize) -> Time {
35		let field = &self.fields()[index];
36		reifydb_assertions! {
37			assert!(
38				row.len() >= self.total_static_size(),
39				"row/shape size mismatch: row.len()={} < total_static_size()={}",
40				row.len(),
41				self.total_static_size()
42			);
43			assert_eq!(*field.constraint.get_type().inner_type(), ValueType::Time);
44		}
45		unsafe {
46			Time::from_nanos_since_midnight(
47				(row.as_ptr().add(field.offset as usize) as *const u64).read_unaligned(),
48			)
49			.unwrap()
50		}
51	}
52
53	pub fn try_get_time(&self, row: &EncodedRow, index: usize) -> Option<Time> {
54		if row.is_defined(index) && self.fields()[index].constraint.get_type() == ValueType::Time {
55			Some(self.get_time(row, index))
56		} else {
57			None
58		}
59	}
60}
61
62#[cfg(test)]
63pub mod tests {
64	use reifydb_value::value::{time::Time, value_type::ValueType};
65
66	use crate::encoded::shape::RowShape;
67
68	#[test]
69	fn test_set_get_time() {
70		let shape = RowShape::testing(&[ValueType::Time]);
71		let mut row = shape.allocate();
72
73		let value = Time::new(20, 50, 0, 0).unwrap();
74		shape.set_time(&mut row, 0, value.clone());
75		assert_eq!(shape.get_time(&row, 0), value);
76	}
77
78	#[test]
79	fn test_try_get_time() {
80		let shape = RowShape::testing(&[ValueType::Time]);
81		let mut row = shape.allocate();
82
83		assert_eq!(shape.try_get_time(&row, 0), None);
84
85		let test_time = Time::from_hms(14, 30, 45).unwrap();
86		shape.set_time(&mut row, 0, test_time.clone());
87		assert_eq!(shape.try_get_time(&row, 0), Some(test_time));
88	}
89
90	#[test]
91	fn test_time_midnight() {
92		let shape = RowShape::testing(&[ValueType::Time]);
93		let mut row = shape.allocate();
94
95		let midnight = Time::default(); // 00:00:00
96		shape.set_time(&mut row, 0, midnight.clone());
97		assert_eq!(shape.get_time(&row, 0), midnight);
98	}
99
100	#[test]
101	fn test_time_with_nanoseconds() {
102		let shape = RowShape::testing(&[ValueType::Time]);
103		let mut row = shape.allocate();
104
105		// Test with high precision nanoseconds
106		let precise_time = Time::new(15, 30, 45, 123456789).unwrap();
107		shape.set_time(&mut row, 0, precise_time.clone());
108		assert_eq!(shape.get_time(&row, 0), precise_time);
109	}
110
111	#[test]
112	fn test_time_various_times() {
113		let shape = RowShape::testing(&[ValueType::Time]);
114
115		let test_times = [
116			Time::new(0, 0, 0, 0).unwrap(),            // Midnight
117			Time::new(12, 0, 0, 0).unwrap(),           // Noon
118			Time::new(23, 59, 59, 999999999).unwrap(), // Just before midnight
119			Time::new(6, 30, 15, 500000000).unwrap(),  // Morning time
120			Time::new(18, 45, 30, 750000000).unwrap(), // Evening time
121		];
122
123		for time in test_times {
124			let mut row = shape.allocate();
125			shape.set_time(&mut row, 0, time.clone());
126			assert_eq!(shape.get_time(&row, 0), time);
127		}
128	}
129
130	#[test]
131	fn test_time_boundary_cases() {
132		let shape = RowShape::testing(&[ValueType::Time]);
133
134		let boundary_times = [
135			Time::new(0, 0, 0, 0).unwrap(), // Start of day
136			Time::new(0, 0, 0, 1).unwrap(), /* One nanosecond
137			                                 * after midnight */
138			Time::new(23, 59, 59, 999999998).unwrap(), // One nanosecond before midnight
139			Time::new(23, 59, 59, 999999999).unwrap(), // Last nanosecond of day
140		];
141
142		for time in boundary_times {
143			let mut row = shape.allocate();
144			shape.set_time(&mut row, 0, time.clone());
145			assert_eq!(shape.get_time(&row, 0), time);
146		}
147	}
148
149	#[test]
150	fn test_time_mixed_with_other_types() {
151		let shape = RowShape::testing(&[ValueType::Time, ValueType::Boolean, ValueType::Time, ValueType::Int4]);
152		let mut row = shape.allocate();
153
154		let time1 = Time::new(9, 15, 30, 0).unwrap();
155		let time2 = Time::new(21, 45, 0, 250000000).unwrap();
156
157		shape.set_time(&mut row, 0, time1.clone());
158		shape.set_bool(&mut row, 1, false);
159		shape.set_time(&mut row, 2, time2.clone());
160		shape.set_i32(&mut row, 3, -999);
161
162		assert_eq!(shape.get_time(&row, 0), time1);
163		assert_eq!(shape.get_bool(&row, 1), false);
164		assert_eq!(shape.get_time(&row, 2), time2);
165		assert_eq!(shape.get_i32(&row, 3), -999);
166	}
167
168	#[test]
169	fn test_time_undefined_handling() {
170		let shape = RowShape::testing(&[ValueType::Time, ValueType::Time]);
171		let mut row = shape.allocate();
172
173		let time = Time::new(16, 20, 45, 333000000).unwrap();
174		shape.set_time(&mut row, 0, time.clone());
175
176		assert_eq!(shape.try_get_time(&row, 0), Some(time));
177		assert_eq!(shape.try_get_time(&row, 1), None);
178
179		shape.set_none(&mut row, 0);
180		assert_eq!(shape.try_get_time(&row, 0), None);
181	}
182
183	#[test]
184	fn test_time_precision_preservation() {
185		let shape = RowShape::testing(&[ValueType::Time]);
186		let mut row = shape.allocate();
187
188		// Test that nanosecond precision is preserved
189		let high_precision = Time::new(12, 34, 56, 987654321).unwrap();
190		shape.set_time(&mut row, 0, high_precision.clone());
191
192		let retrieved = shape.get_time(&row, 0);
193		assert_eq!(retrieved, high_precision);
194		assert_eq!(retrieved.to_nanos_since_midnight(), high_precision.to_nanos_since_midnight());
195	}
196
197	#[test]
198	fn test_time_microsecond_precision() {
199		let shape = RowShape::testing(&[ValueType::Time]);
200		let mut row = shape.allocate();
201
202		// Test microsecond precision (common in databases)
203		let microsecond_precision = Time::new(14, 25, 30, 123456000).unwrap();
204		shape.set_time(&mut row, 0, microsecond_precision.clone());
205		assert_eq!(shape.get_time(&row, 0), microsecond_precision);
206	}
207
208	#[test]
209	fn test_time_millisecond_precision() {
210		let shape = RowShape::testing(&[ValueType::Time]);
211		let mut row = shape.allocate();
212
213		// Test millisecond precision
214		let millisecond_precision = Time::new(8, 15, 42, 123000000).unwrap();
215		shape.set_time(&mut row, 0, millisecond_precision.clone());
216		assert_eq!(shape.get_time(&row, 0), millisecond_precision);
217	}
218
219	#[test]
220	fn test_time_common_times() {
221		let shape = RowShape::testing(&[ValueType::Time]);
222
223		// Test common business/system times
224		let common_times = [
225			Time::new(9, 0, 0, 0).unwrap(),   // 9 AM start of work
226			Time::new(12, 0, 0, 0).unwrap(),  // Noon
227			Time::new(17, 0, 0, 0).unwrap(),  // 5 PM end of work
228			Time::new(0, 0, 1, 0).unwrap(),   // 1 second after midnight
229			Time::new(23, 59, 0, 0).unwrap(), // 1 minute before midnight
230		];
231
232		for time in common_times {
233			let mut row = shape.allocate();
234			shape.set_time(&mut row, 0, time.clone());
235			assert_eq!(shape.get_time(&row, 0), time);
236		}
237	}
238
239	#[test]
240	fn test_try_get_time_wrong_type() {
241		let shape = RowShape::testing(&[ValueType::Boolean]);
242		let mut row = shape.allocate();
243
244		shape.set_bool(&mut row, 0, true);
245
246		assert_eq!(shape.try_get_time(&row, 0), None);
247	}
248}