reifydb_core/value/encoded/
time.rs

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