Skip to main content

reifydb_core/value/index/
get.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4use std::ptr;
5
6#[cfg(reifydb_assertions)]
7use reifydb_value::value::value_type::ValueType;
8use reifydb_value::{
9	reifydb_assertions,
10	value::{
11		date::Date,
12		datetime::DateTime,
13		duration::Duration,
14		identity::IdentityId,
15		time::Time,
16		uuid::{Uuid4, Uuid7},
17	},
18};
19use uuid::Uuid;
20
21use crate::{
22	sort::SortDirection,
23	value::index::{encoded::EncodedIndexKey, shape::IndexShape},
24};
25
26impl IndexShape {
27	pub fn get_bool(&self, key: &EncodedIndexKey, index: usize) -> bool {
28		let field = &self.fields[index];
29		reifydb_assertions! {
30			assert_eq!(field.value, ValueType::Boolean);
31		}
32
33		// SAFETY: `key` is laid out by this shape, so `field.offset < total_size == key.len()`;
34		// reading a single `u8` needs alignment 1.
35		let byte = unsafe { *key.as_ptr().add(field.offset) };
36
37		match field.direction {
38			SortDirection::Asc => byte != 0,
39			SortDirection::Desc => byte == 0,
40		}
41	}
42
43	pub fn get_f32(&self, key: &EncodedIndexKey, index: usize) -> f32 {
44		let field = &self.fields[index];
45		reifydb_assertions! {
46			assert_eq!(field.value, ValueType::Float4);
47		}
48
49		let mut bytes = [0u8; 4];
50		// SAFETY: `key` is laid out by this shape, so `field.offset + 4 <= total_size == key.len()`;
51		// the copy is byte-wise through `*const u8`, so alignment 1 suffices.
52		unsafe {
53			ptr::copy_nonoverlapping(key.as_ptr().add(field.offset), bytes.as_mut_ptr(), 4);
54		}
55
56		if field.direction == SortDirection::Desc {
57			for b in bytes.iter_mut() {
58				*b = !*b;
59			}
60		}
61
62		if bytes[0] & 0x80 != 0 {
63			bytes[0] ^= 0x80;
64		} else {
65			for b in bytes.iter_mut() {
66				*b = !*b;
67			}
68		}
69
70		f32::from_bits(u32::from_be_bytes(bytes))
71	}
72
73	pub fn get_f64(&self, key: &EncodedIndexKey, index: usize) -> f64 {
74		let field = &self.fields[index];
75		reifydb_assertions! {
76			assert_eq!(field.value, ValueType::Float8);
77		}
78
79		let mut bytes = [0u8; 8];
80		// SAFETY: `key` is laid out by this shape, so `field.offset + 8 <= total_size == key.len()`;
81		// the copy is byte-wise through `*const u8`, so alignment 1 suffices.
82		unsafe {
83			ptr::copy_nonoverlapping(key.as_ptr().add(field.offset), bytes.as_mut_ptr(), 8);
84		}
85
86		if field.direction == SortDirection::Desc {
87			for b in bytes.iter_mut() {
88				*b = !*b;
89			}
90		}
91
92		if bytes[0] & 0x80 != 0 {
93			bytes[0] ^= 0x80;
94		} else {
95			for b in bytes.iter_mut() {
96				*b = !*b;
97			}
98		}
99
100		f64::from_bits(u64::from_be_bytes(bytes))
101	}
102
103	pub fn get_i8(&self, key: &EncodedIndexKey, index: usize) -> i8 {
104		let field = &self.fields[index];
105		reifydb_assertions! {
106			assert_eq!(field.value, ValueType::Int1);
107		}
108
109		// SAFETY: `key` is laid out by this shape, so `field.offset < total_size == key.len()`;
110		// reading a single `u8` needs alignment 1.
111		let mut byte = unsafe { *key.as_ptr().add(field.offset) };
112
113		match field.direction {
114			SortDirection::Asc => {
115				byte ^= 0x80;
116			}
117			SortDirection::Desc => {
118				byte = !byte;
119				byte ^= 0x80;
120			}
121		}
122
123		i8::from_be_bytes([byte])
124	}
125
126	pub fn get_i16(&self, key: &EncodedIndexKey, index: usize) -> i16 {
127		let field = &self.fields[index];
128		reifydb_assertions! {
129			assert_eq!(field.value, ValueType::Int2);
130		}
131
132		let mut bytes = [0u8; 2];
133		// SAFETY: `key` is laid out by this shape, so `field.offset + 2 <= total_size == key.len()`;
134		// the copy is byte-wise through `*const u8`, so alignment 1 suffices.
135		unsafe {
136			ptr::copy_nonoverlapping(key.as_ptr().add(field.offset), bytes.as_mut_ptr(), 2);
137		}
138
139		match field.direction {
140			SortDirection::Asc => {
141				bytes[0] ^= 0x80;
142			}
143			SortDirection::Desc => {
144				for b in bytes.iter_mut() {
145					*b = !*b;
146				}
147				bytes[0] ^= 0x80;
148			}
149		}
150
151		i16::from_be_bytes(bytes)
152	}
153
154	pub fn get_i32(&self, key: &EncodedIndexKey, index: usize) -> i32 {
155		let field = &self.fields[index];
156		reifydb_assertions! {
157			assert_eq!(field.value, ValueType::Int4);
158		}
159
160		let mut bytes = [0u8; 4];
161		// SAFETY: `key` is laid out by this shape, so `field.offset + 4 <= total_size == key.len()`;
162		// the copy is byte-wise through `*const u8`, so alignment 1 suffices.
163		unsafe {
164			ptr::copy_nonoverlapping(key.as_ptr().add(field.offset), bytes.as_mut_ptr(), 4);
165		}
166
167		match field.direction {
168			SortDirection::Asc => {
169				bytes[0] ^= 0x80;
170			}
171			SortDirection::Desc => {
172				for b in bytes.iter_mut() {
173					*b = !*b;
174				}
175				bytes[0] ^= 0x80;
176			}
177		}
178
179		i32::from_be_bytes(bytes)
180	}
181
182	pub fn get_i64(&self, key: &EncodedIndexKey, index: usize) -> i64 {
183		let field = &self.fields[index];
184		reifydb_assertions! {
185			assert_eq!(field.value, ValueType::Int8);
186		}
187
188		let mut bytes = [0u8; 8];
189		// SAFETY: `key` is laid out by this shape, so `field.offset + 8 <= total_size == key.len()`;
190		// the copy is byte-wise through `*const u8`, so alignment 1 suffices.
191		unsafe {
192			ptr::copy_nonoverlapping(key.as_ptr().add(field.offset), bytes.as_mut_ptr(), 8);
193		}
194
195		match field.direction {
196			SortDirection::Asc => {
197				bytes[0] ^= 0x80;
198			}
199			SortDirection::Desc => {
200				for b in bytes.iter_mut() {
201					*b = !*b;
202				}
203				bytes[0] ^= 0x80;
204			}
205		}
206
207		i64::from_be_bytes(bytes)
208	}
209
210	pub fn get_i128(&self, key: &EncodedIndexKey, index: usize) -> i128 {
211		let field = &self.fields[index];
212		reifydb_assertions! {
213			assert_eq!(field.value, ValueType::Int16);
214		}
215
216		let mut bytes = [0u8; 16];
217		// SAFETY: `key` is laid out by this shape, so `field.offset + 16 <= total_size == key.len()`;
218		// the copy is byte-wise through `*const u8`, so alignment 1 suffices.
219		unsafe {
220			ptr::copy_nonoverlapping(key.as_ptr().add(field.offset), bytes.as_mut_ptr(), 16);
221		}
222
223		match field.direction {
224			SortDirection::Asc => {
225				bytes[0] ^= 0x80;
226			}
227			SortDirection::Desc => {
228				for b in bytes.iter_mut() {
229					*b = !*b;
230				}
231				bytes[0] ^= 0x80;
232			}
233		}
234
235		i128::from_be_bytes(bytes)
236	}
237
238	pub fn get_u8(&self, key: &EncodedIndexKey, index: usize) -> u8 {
239		let field = &self.fields[index];
240		reifydb_assertions! {
241			assert_eq!(field.value, ValueType::Uint1);
242		}
243
244		// SAFETY: `key` is laid out by this shape, so `field.offset < total_size == key.len()`;
245		// reading a single `u8` needs alignment 1.
246		let byte = unsafe { *key.as_ptr().add(field.offset) };
247
248		match field.direction {
249			SortDirection::Asc => byte,
250			SortDirection::Desc => !byte,
251		}
252	}
253
254	pub fn get_u16(&self, key: &EncodedIndexKey, index: usize) -> u16 {
255		let field = &self.fields[index];
256		reifydb_assertions! {
257			assert_eq!(field.value, ValueType::Uint2);
258		}
259
260		let mut bytes = [0u8; 2];
261		// SAFETY: `key` is laid out by this shape, so `field.offset + 2 <= total_size == key.len()`;
262		// the copy is byte-wise through `*const u8`, so alignment 1 suffices.
263		unsafe {
264			ptr::copy_nonoverlapping(key.as_ptr().add(field.offset), bytes.as_mut_ptr(), 2);
265		}
266
267		match field.direction {
268			SortDirection::Asc => u16::from_be_bytes(bytes),
269			SortDirection::Desc => !u16::from_be_bytes(bytes),
270		}
271	}
272
273	pub fn get_u32(&self, key: &EncodedIndexKey, index: usize) -> u32 {
274		let field = &self.fields[index];
275		reifydb_assertions! {
276			assert_eq!(field.value, ValueType::Uint4);
277		}
278
279		let mut bytes = [0u8; 4];
280		// SAFETY: `key` is laid out by this shape, so `field.offset + 4 <= total_size == key.len()`;
281		// the copy is byte-wise through `*const u8`, so alignment 1 suffices.
282		unsafe {
283			ptr::copy_nonoverlapping(key.as_ptr().add(field.offset), bytes.as_mut_ptr(), 4);
284		}
285
286		match field.direction {
287			SortDirection::Asc => u32::from_be_bytes(bytes),
288			SortDirection::Desc => !u32::from_be_bytes(bytes),
289		}
290	}
291
292	pub fn get_u64(&self, key: &EncodedIndexKey, index: usize) -> u64 {
293		let field = &self.fields[index];
294		reifydb_assertions! {
295			assert_eq!(field.value, ValueType::Uint8);
296		}
297
298		let mut bytes = [0u8; 8];
299		// SAFETY: `key` is laid out by this shape, so `field.offset + 8 <= total_size == key.len()`;
300		// the copy is byte-wise through `*const u8`, so alignment 1 suffices.
301		unsafe {
302			ptr::copy_nonoverlapping(key.as_ptr().add(field.offset), bytes.as_mut_ptr(), 8);
303		}
304
305		match field.direction {
306			SortDirection::Asc => u64::from_be_bytes(bytes),
307			SortDirection::Desc => !u64::from_be_bytes(bytes),
308		}
309	}
310
311	pub fn get_u128(&self, key: &EncodedIndexKey, index: usize) -> u128 {
312		let field = &self.fields[index];
313		reifydb_assertions! {
314			assert_eq!(field.value, ValueType::Uint16);
315		}
316
317		let mut bytes = [0u8; 16];
318		// SAFETY: `key` is laid out by this shape, so `field.offset + 16 <= total_size == key.len()`;
319		// the copy is byte-wise through `*const u8`, so alignment 1 suffices.
320		unsafe {
321			ptr::copy_nonoverlapping(key.as_ptr().add(field.offset), bytes.as_mut_ptr(), 16);
322		}
323
324		match field.direction {
325			SortDirection::Asc => u128::from_be_bytes(bytes),
326			SortDirection::Desc => !u128::from_be_bytes(bytes),
327		}
328	}
329
330	pub fn get_row_number(&self, key: &EncodedIndexKey, index: usize) -> u64 {
331		let field = &self.fields[index];
332		reifydb_assertions! {
333			assert_eq!(field.value, ValueType::Uint8);
334		}
335
336		let mut bytes = [0u8; 8];
337		// SAFETY: `key` is laid out by this shape, so `field.offset + 8 <= total_size == key.len()`;
338		// the copy is byte-wise through `*const u8`, so alignment 1 suffices.
339		unsafe {
340			ptr::copy_nonoverlapping(key.as_ptr().add(field.offset), bytes.as_mut_ptr(), 8);
341		}
342
343		match field.direction {
344			SortDirection::Asc => u64::from_be_bytes(bytes),
345			SortDirection::Desc => !u64::from_be_bytes(bytes),
346		}
347	}
348
349	pub fn get_date(&self, key: &EncodedIndexKey, index: usize) -> Date {
350		let field = &self.fields[index];
351		reifydb_assertions! {
352			assert_eq!(field.value, ValueType::Date);
353		}
354
355		let mut bytes = [0u8; 4];
356		// SAFETY: `key` is laid out by this shape, so `field.offset + 4 <= total_size == key.len()`;
357		// the copy is byte-wise through `*const u8`, so alignment 1 suffices.
358		unsafe {
359			ptr::copy_nonoverlapping(key.as_ptr().add(field.offset), bytes.as_mut_ptr(), 4);
360		}
361
362		match field.direction {
363			SortDirection::Asc => {
364				bytes[0] ^= 0x80;
365			}
366			SortDirection::Desc => {
367				for b in bytes.iter_mut() {
368					*b = !*b;
369				}
370				bytes[0] ^= 0x80;
371			}
372		}
373
374		let days = i32::from_be_bytes(bytes);
375		Date::from_days_since_epoch(days).unwrap()
376	}
377
378	pub fn get_datetime(&self, key: &EncodedIndexKey, index: usize) -> DateTime {
379		let field = &self.fields[index];
380		reifydb_assertions! {
381			assert_eq!(field.value, ValueType::DateTime);
382		}
383
384		let mut bytes = [0u8; 8];
385
386		// SAFETY: `key` is laid out by this shape, so `field.offset + 8 <= total_size == key.len()`;
387		// the copy is byte-wise through `*const u8`, so alignment 1 suffices.
388		unsafe {
389			ptr::copy_nonoverlapping(key.as_ptr().add(field.offset), bytes.as_mut_ptr(), 8);
390		}
391
392		let nanos = match field.direction {
393			SortDirection::Asc => u64::from_be_bytes(bytes),
394			SortDirection::Desc => !u64::from_be_bytes(bytes),
395		};
396
397		DateTime::from_nanos(nanos)
398	}
399
400	pub fn get_time(&self, key: &EncodedIndexKey, index: usize) -> Time {
401		let field = &self.fields[index];
402		reifydb_assertions! {
403			assert_eq!(field.value, ValueType::Time);
404		}
405
406		let mut bytes = [0u8; 8];
407		// SAFETY: `key` is laid out by this shape, so `field.offset + 8 <= total_size == key.len()`;
408		// the copy is byte-wise through `*const u8`, so alignment 1 suffices.
409		unsafe {
410			ptr::copy_nonoverlapping(key.as_ptr().add(field.offset), bytes.as_mut_ptr(), 8);
411		}
412
413		let nanos = match field.direction {
414			SortDirection::Asc => u64::from_be_bytes(bytes),
415			SortDirection::Desc => !u64::from_be_bytes(bytes),
416		};
417
418		Time::from_nanos_since_midnight(nanos).unwrap()
419	}
420
421	pub fn get_duration(&self, key: &EncodedIndexKey, index: usize) -> Duration {
422		let field = &self.fields[index];
423		reifydb_assertions! {
424			assert_eq!(field.value, ValueType::Duration);
425		}
426
427		let mut months_bytes = [0u8; 4];
428		let mut days_bytes = [0u8; 4];
429		let mut nanos_bytes = [0u8; 8];
430
431		// SAFETY: `key` is laid out by this shape, so `field.offset + 16 <= total_size == key.len()`
432		// covers all three copies; the copies are byte-wise, so alignment 1 suffices.
433		unsafe {
434			ptr::copy_nonoverlapping(key.as_ptr().add(field.offset), months_bytes.as_mut_ptr(), 4);
435			ptr::copy_nonoverlapping(key.as_ptr().add(field.offset + 4), days_bytes.as_mut_ptr(), 4);
436			ptr::copy_nonoverlapping(key.as_ptr().add(field.offset + 8), nanos_bytes.as_mut_ptr(), 8);
437		}
438
439		match field.direction {
440			SortDirection::Asc => {
441				months_bytes[0] ^= 0x80;
442				days_bytes[0] ^= 0x80;
443				nanos_bytes[0] ^= 0x80;
444			}
445			SortDirection::Desc => {
446				for b in months_bytes.iter_mut() {
447					*b = !*b;
448				}
449				months_bytes[0] ^= 0x80;
450				for b in days_bytes.iter_mut() {
451					*b = !*b;
452				}
453				days_bytes[0] ^= 0x80;
454				for b in nanos_bytes.iter_mut() {
455					*b = !*b;
456				}
457				nanos_bytes[0] ^= 0x80;
458			}
459		}
460
461		let months = i32::from_be_bytes(months_bytes);
462		let days = i32::from_be_bytes(days_bytes);
463		let nanos = i64::from_be_bytes(nanos_bytes);
464		Duration::new(months, days, nanos).expect("stored duration must be valid")
465	}
466
467	pub fn get_uuid4(&self, key: &EncodedIndexKey, index: usize) -> Uuid4 {
468		let field = &self.fields[index];
469		reifydb_assertions! {
470			assert_eq!(field.value, ValueType::Uuid4);
471		}
472
473		let mut bytes = [0u8; 16];
474		// SAFETY: `key` is laid out by this shape, so `field.offset + 16 <= total_size == key.len()`;
475		// the copy is byte-wise through `*const u8`, so alignment 1 suffices.
476		unsafe {
477			ptr::copy_nonoverlapping(key.as_ptr().add(field.offset), bytes.as_mut_ptr(), 16);
478		}
479
480		if field.direction == SortDirection::Desc {
481			for b in bytes.iter_mut() {
482				*b = !*b;
483			}
484		}
485
486		let uuid = Uuid::from_bytes(bytes);
487		Uuid4::from(uuid)
488	}
489
490	pub fn get_uuid7(&self, key: &EncodedIndexKey, index: usize) -> Uuid7 {
491		let field = &self.fields[index];
492		reifydb_assertions! {
493			assert_eq!(field.value, ValueType::Uuid7);
494		}
495
496		let mut bytes = [0u8; 16];
497		// SAFETY: `key` is laid out by this shape, so `field.offset + 16 <= total_size == key.len()`;
498		// the copy is byte-wise through `*const u8`, so alignment 1 suffices.
499		unsafe {
500			ptr::copy_nonoverlapping(key.as_ptr().add(field.offset), bytes.as_mut_ptr(), 16);
501		}
502
503		if field.direction == SortDirection::Desc {
504			for b in bytes.iter_mut() {
505				*b = !*b;
506			}
507		}
508
509		let uuid = Uuid::from_bytes(bytes);
510		Uuid7::from(uuid)
511	}
512
513	pub fn get_identity_id(&self, key: &EncodedIndexKey, index: usize) -> IdentityId {
514		let field = &self.fields[index];
515		reifydb_assertions! {
516			assert_eq!(field.value, ValueType::IdentityId);
517		}
518
519		let mut bytes = [0u8; 16];
520		// SAFETY: `key` is laid out by this shape, so `field.offset + 16 <= total_size == key.len()`;
521		// the copy is byte-wise through `*const u8`, so alignment 1 suffices.
522		unsafe {
523			ptr::copy_nonoverlapping(key.as_ptr().add(field.offset), bytes.as_mut_ptr(), 16);
524		}
525
526		if field.direction == SortDirection::Desc {
527			for b in bytes.iter_mut() {
528				*b = !*b;
529			}
530		}
531
532		let uuid = Uuid::from_bytes(bytes);
533		let uuid7 = Uuid7::from(uuid);
534		IdentityId::from(uuid7)
535	}
536}
537
538#[cfg(test)]
539pub mod tests {
540	use reifydb_value::value::value_type::ValueType;
541
542	use crate::{sort::SortDirection, value::index::shape::IndexShape};
543
544	mod bool {
545		use super::*;
546
547		#[test]
548		fn test_asc() {
549			let layout = IndexShape::new(&[ValueType::Boolean], &[SortDirection::Asc]).unwrap();
550			let mut key1 = layout.allocate_key();
551			let mut key2 = layout.allocate_key();
552
553			layout.set_bool(&mut key1, 0, false);
554			layout.set_bool(&mut key2, 0, true);
555
556			assert!(key1.as_slice() < key2.as_slice());
557			assert_eq!(layout.get_bool(&key1, 0), false);
558			assert_eq!(layout.get_bool(&key2, 0), true);
559		}
560
561		#[test]
562		fn test_desc() {
563			let layout = IndexShape::new(&[ValueType::Boolean], &[SortDirection::Desc]).unwrap();
564			let mut key1 = layout.allocate_key();
565			let mut key2 = layout.allocate_key();
566
567			layout.set_bool(&mut key1, 0, false);
568			layout.set_bool(&mut key2, 0, true);
569
570			assert!(key1.as_slice() > key2.as_slice());
571			assert_eq!(layout.get_bool(&key1, 0), false);
572			assert_eq!(layout.get_bool(&key2, 0), true);
573		}
574	}
575
576	mod i8 {
577		use reifydb_value::value::value_type::ValueType;
578
579		use crate::{sort::SortDirection, value::index::shape::IndexShape};
580
581		#[test]
582		fn test_asc() {
583			let layout = IndexShape::new(&[ValueType::Int1], &[SortDirection::Asc]).unwrap();
584			let mut key1 = layout.allocate_key();
585			let mut key2 = layout.allocate_key();
586			let mut key3 = layout.allocate_key();
587
588			layout.set_i8(&mut key1, 0, -10i8);
589			layout.set_i8(&mut key2, 0, 0i8);
590			layout.set_i8(&mut key3, 0, 10i8);
591
592			assert!(key1.as_slice() < key2.as_slice());
593			assert!(key2.as_slice() < key3.as_slice());
594			assert_eq!(layout.get_i8(&key1, 0), -10);
595			assert_eq!(layout.get_i8(&key2, 0), 0);
596			assert_eq!(layout.get_i8(&key3, 0), 10);
597		}
598
599		#[test]
600		fn test_desc() {
601			let layout = IndexShape::new(&[ValueType::Int1], &[SortDirection::Desc]).unwrap();
602			let mut key1 = layout.allocate_key();
603			let mut key2 = layout.allocate_key();
604			let mut key3 = layout.allocate_key();
605
606			layout.set_i8(&mut key1, 0, -10i8);
607			layout.set_i8(&mut key2, 0, 0i8);
608			layout.set_i8(&mut key3, 0, 10i8);
609
610			assert!(key1.as_slice() > key2.as_slice());
611			assert!(key2.as_slice() > key3.as_slice());
612			assert_eq!(layout.get_i8(&key1, 0), -10);
613			assert_eq!(layout.get_i8(&key2, 0), 0);
614			assert_eq!(layout.get_i8(&key3, 0), 10);
615		}
616	}
617
618	mod i32 {
619		use reifydb_value::value::value_type::ValueType;
620
621		use crate::{sort::SortDirection, value::index::shape::IndexShape};
622
623		#[test]
624		fn test_asc() {
625			let layout = IndexShape::new(&[ValueType::Int4], &[SortDirection::Asc]).unwrap();
626			let mut key1 = layout.allocate_key();
627			let mut key2 = layout.allocate_key();
628			let mut key3 = layout.allocate_key();
629
630			layout.set_i32(&mut key1, 0, -1000i32);
631			layout.set_i32(&mut key2, 0, 0i32);
632			layout.set_i32(&mut key3, 0, 1000i32);
633
634			assert!(key1.as_slice() < key2.as_slice());
635			assert!(key2.as_slice() < key3.as_slice());
636			assert_eq!(layout.get_i32(&key1, 0), -1000);
637			assert_eq!(layout.get_i32(&key2, 0), 0);
638			assert_eq!(layout.get_i32(&key3, 0), 1000);
639		}
640
641		#[test]
642		fn test_desc() {
643			let layout = IndexShape::new(&[ValueType::Int4], &[SortDirection::Desc]).unwrap();
644			let mut key1 = layout.allocate_key();
645			let mut key2 = layout.allocate_key();
646			let mut key3 = layout.allocate_key();
647
648			layout.set_i32(&mut key1, 0, -1000i32);
649			layout.set_i32(&mut key2, 0, 0i32);
650			layout.set_i32(&mut key3, 0, 1000i32);
651
652			assert!(key1.as_slice() > key2.as_slice());
653			assert!(key2.as_slice() > key3.as_slice());
654			assert_eq!(layout.get_i32(&key1, 0), -1000);
655			assert_eq!(layout.get_i32(&key2, 0), 0);
656			assert_eq!(layout.get_i32(&key3, 0), 1000);
657		}
658	}
659
660	mod i64 {
661		use reifydb_value::value::value_type::ValueType;
662
663		use crate::{sort::SortDirection, value::index::shape::IndexShape};
664
665		#[test]
666		fn test_asc() {
667			let layout = IndexShape::new(&[ValueType::Int8], &[SortDirection::Asc]).unwrap();
668			let mut key1 = layout.allocate_key();
669			let mut key2 = layout.allocate_key();
670			let mut key3 = layout.allocate_key();
671
672			layout.set_i64(&mut key1, 0, i64::MIN);
673			layout.set_i64(&mut key2, 0, 0i64);
674			layout.set_i64(&mut key3, 0, i64::MAX);
675
676			assert!(key1.as_slice() < key2.as_slice());
677			assert!(key2.as_slice() < key3.as_slice());
678			assert_eq!(layout.get_i64(&key1, 0), i64::MIN);
679			assert_eq!(layout.get_i64(&key2, 0), 0);
680			assert_eq!(layout.get_i64(&key3, 0), i64::MAX);
681		}
682
683		#[test]
684		fn test_desc() {
685			let layout = IndexShape::new(&[ValueType::Int8], &[SortDirection::Desc]).unwrap();
686			let mut key1 = layout.allocate_key();
687			let mut key2 = layout.allocate_key();
688			let mut key3 = layout.allocate_key();
689
690			layout.set_i64(&mut key1, 0, i64::MIN);
691			layout.set_i64(&mut key2, 0, 0i64);
692			layout.set_i64(&mut key3, 0, i64::MAX);
693
694			assert!(key1.as_slice() > key2.as_slice());
695			assert!(key2.as_slice() > key3.as_slice());
696			assert_eq!(layout.get_i64(&key1, 0), i64::MIN);
697			assert_eq!(layout.get_i64(&key2, 0), 0);
698			assert_eq!(layout.get_i64(&key3, 0), i64::MAX);
699		}
700	}
701
702	mod u8 {
703		use reifydb_value::value::value_type::ValueType;
704
705		use crate::{sort::SortDirection, value::index::shape::IndexShape};
706
707		#[test]
708		fn test_asc() {
709			let layout = IndexShape::new(&[ValueType::Uint1], &[SortDirection::Asc]).unwrap();
710			let mut key1 = layout.allocate_key();
711			let mut key2 = layout.allocate_key();
712			let mut key3 = layout.allocate_key();
713
714			layout.set_u8(&mut key1, 0, 0u8);
715			layout.set_u8(&mut key2, 0, 128u8);
716			layout.set_u8(&mut key3, 0, 255u8);
717
718			assert!(key1.as_slice() < key2.as_slice());
719			assert!(key2.as_slice() < key3.as_slice());
720			assert_eq!(layout.get_u8(&key1, 0), 0);
721			assert_eq!(layout.get_u8(&key2, 0), 128);
722			assert_eq!(layout.get_u8(&key3, 0), 255);
723		}
724
725		#[test]
726		fn test_desc() {
727			let layout = IndexShape::new(&[ValueType::Uint1], &[SortDirection::Desc]).unwrap();
728			let mut key1 = layout.allocate_key();
729			let mut key2 = layout.allocate_key();
730			let mut key3 = layout.allocate_key();
731
732			layout.set_u8(&mut key1, 0, 0u8);
733			layout.set_u8(&mut key2, 0, 128u8);
734			layout.set_u8(&mut key3, 0, 255u8);
735
736			assert!(key1.as_slice() > key2.as_slice());
737			assert!(key2.as_slice() > key3.as_slice());
738			assert_eq!(layout.get_u8(&key1, 0), 0);
739			assert_eq!(layout.get_u8(&key2, 0), 128);
740			assert_eq!(layout.get_u8(&key3, 0), 255);
741		}
742	}
743
744	mod u32 {
745		use reifydb_value::value::value_type::ValueType;
746
747		use crate::{sort::SortDirection, value::index::shape::IndexShape};
748
749		#[test]
750		fn test_asc() {
751			let layout = IndexShape::new(&[ValueType::Uint4], &[SortDirection::Asc]).unwrap();
752			let mut key1 = layout.allocate_key();
753			let mut key2 = layout.allocate_key();
754			let mut key3 = layout.allocate_key();
755
756			layout.set_u32(&mut key1, 0, 0u32);
757			layout.set_u32(&mut key2, 0, 1000000u32);
758			layout.set_u32(&mut key3, 0, u32::MAX);
759
760			assert!(key1.as_slice() < key2.as_slice());
761			assert!(key2.as_slice() < key3.as_slice());
762			assert_eq!(layout.get_u32(&key1, 0), 0);
763			assert_eq!(layout.get_u32(&key2, 0), 1000000);
764			assert_eq!(layout.get_u32(&key3, 0), u32::MAX);
765		}
766
767		#[test]
768		fn test_desc() {
769			let layout = IndexShape::new(&[ValueType::Uint4], &[SortDirection::Desc]).unwrap();
770			let mut key1 = layout.allocate_key();
771			let mut key2 = layout.allocate_key();
772			let mut key3 = layout.allocate_key();
773
774			layout.set_u32(&mut key1, 0, 0u32);
775			layout.set_u32(&mut key2, 0, 1000000u32);
776			layout.set_u32(&mut key3, 0, u32::MAX);
777
778			assert!(key1.as_slice() > key2.as_slice());
779			assert!(key2.as_slice() > key3.as_slice());
780			assert_eq!(layout.get_u32(&key1, 0), 0);
781			assert_eq!(layout.get_u32(&key2, 0), 1000000);
782			assert_eq!(layout.get_u32(&key3, 0), u32::MAX);
783		}
784	}
785
786	mod u64 {
787		use reifydb_value::value::value_type::ValueType;
788
789		use crate::{sort::SortDirection, value::index::shape::IndexShape};
790
791		#[test]
792		fn test_asc() {
793			let layout = IndexShape::new(&[ValueType::Uint8], &[SortDirection::Asc]).unwrap();
794			let mut key1 = layout.allocate_key();
795			let mut key2 = layout.allocate_key();
796			let mut key3 = layout.allocate_key();
797
798			layout.set_u64(&mut key1, 0, 0u64);
799			layout.set_u64(&mut key2, 0, 1_000_000_000u64);
800			layout.set_u64(&mut key3, 0, u64::MAX);
801
802			assert!(key1.as_slice() < key2.as_slice());
803			assert!(key2.as_slice() < key3.as_slice());
804			assert_eq!(layout.get_u64(&key1, 0), 0);
805			assert_eq!(layout.get_u64(&key2, 0), 1_000_000_000);
806			assert_eq!(layout.get_u64(&key3, 0), u64::MAX);
807		}
808
809		#[test]
810		fn test_desc() {
811			let layout = IndexShape::new(&[ValueType::Uint8], &[SortDirection::Desc]).unwrap();
812			let mut key1 = layout.allocate_key();
813			let mut key2 = layout.allocate_key();
814			let mut key3 = layout.allocate_key();
815
816			layout.set_u64(&mut key1, 0, 0u64);
817			layout.set_u64(&mut key2, 0, 1_000_000_000u64);
818			layout.set_u64(&mut key3, 0, u64::MAX);
819
820			assert!(key1.as_slice() > key2.as_slice());
821			assert!(key2.as_slice() > key3.as_slice());
822			assert_eq!(layout.get_u64(&key1, 0), 0);
823			assert_eq!(layout.get_u64(&key2, 0), 1_000_000_000);
824			assert_eq!(layout.get_u64(&key3, 0), u64::MAX);
825		}
826	}
827
828	mod f32 {
829		use reifydb_value::value::value_type::ValueType;
830
831		use crate::{sort::SortDirection, value::index::shape::IndexShape};
832
833		#[test]
834		fn test_asc() {
835			let layout = IndexShape::new(&[ValueType::Float4], &[SortDirection::Asc]).unwrap();
836			let mut key1 = layout.allocate_key();
837			let mut key2 = layout.allocate_key();
838			let mut key3 = layout.allocate_key();
839
840			layout.set_f32(&mut key1, 0, -100.5f32);
841			layout.set_f32(&mut key2, 0, 0.0f32);
842			layout.set_f32(&mut key3, 0, 100.5f32);
843
844			assert!(key1.as_slice() < key2.as_slice());
845			assert!(key2.as_slice() < key3.as_slice());
846			assert_eq!(layout.get_f32(&key1, 0), -100.5);
847			assert_eq!(layout.get_f32(&key2, 0), 0.0);
848			assert_eq!(layout.get_f32(&key3, 0), 100.5);
849		}
850
851		#[test]
852		fn test_desc() {
853			let layout = IndexShape::new(&[ValueType::Float4], &[SortDirection::Desc]).unwrap();
854			let mut key1 = layout.allocate_key();
855			let mut key2 = layout.allocate_key();
856			let mut key3 = layout.allocate_key();
857
858			layout.set_f32(&mut key1, 0, -100.5f32);
859			layout.set_f32(&mut key2, 0, 0.0f32);
860			layout.set_f32(&mut key3, 0, 100.5f32);
861
862			assert!(key1.as_slice() > key2.as_slice());
863			assert!(key2.as_slice() > key3.as_slice());
864			assert_eq!(layout.get_f32(&key1, 0), -100.5);
865			assert_eq!(layout.get_f32(&key2, 0), 0.0);
866			assert_eq!(layout.get_f32(&key3, 0), 100.5);
867		}
868	}
869
870	mod f64 {
871		use reifydb_value::value::value_type::ValueType;
872
873		use crate::{sort::SortDirection, value::index::shape::IndexShape};
874
875		#[test]
876		fn test_asc() {
877			let layout = IndexShape::new(&[ValueType::Float8], &[SortDirection::Asc]).unwrap();
878			let mut key1 = layout.allocate_key();
879			let mut key2 = layout.allocate_key();
880			let mut key3 = layout.allocate_key();
881
882			layout.set_f64(&mut key1, 0, -1000.123456f64);
883			layout.set_f64(&mut key2, 0, 0.0f64);
884			layout.set_f64(&mut key3, 0, 1000.123456f64);
885
886			assert!(key1.as_slice() < key2.as_slice());
887			assert!(key2.as_slice() < key3.as_slice());
888			assert_eq!(layout.get_f64(&key1, 0), -1000.123456);
889			assert_eq!(layout.get_f64(&key2, 0), 0.0);
890			assert_eq!(layout.get_f64(&key3, 0), 1000.123456);
891		}
892
893		#[test]
894		fn test_desc() {
895			let layout = IndexShape::new(&[ValueType::Float8], &[SortDirection::Desc]).unwrap();
896			let mut key1 = layout.allocate_key();
897			let mut key2 = layout.allocate_key();
898			let mut key3 = layout.allocate_key();
899
900			layout.set_f64(&mut key1, 0, -1000.123456f64);
901			layout.set_f64(&mut key2, 0, 0.0f64);
902			layout.set_f64(&mut key3, 0, 1000.123456f64);
903
904			assert!(key1.as_slice() > key2.as_slice());
905			assert!(key2.as_slice() > key3.as_slice());
906			assert_eq!(layout.get_f64(&key1, 0), -1000.123456);
907			assert_eq!(layout.get_f64(&key2, 0), 0.0);
908			assert_eq!(layout.get_f64(&key3, 0), 1000.123456);
909		}
910	}
911
912	mod date {
913		use reifydb_value::value::{date::Date, value_type::ValueType};
914
915		use crate::{sort::SortDirection, value::index::shape::IndexShape};
916
917		#[test]
918		fn test_asc() {
919			let layout = IndexShape::new(&[ValueType::Date], &[SortDirection::Asc]).unwrap();
920			let mut key1 = layout.allocate_key();
921			let mut key2 = layout.allocate_key();
922			let mut key3 = layout.allocate_key();
923
924			let date1 = Date::new(2020, 1, 1).unwrap();
925			let date2 = Date::new(2023, 6, 15).unwrap();
926			let date3 = Date::new(2025, 12, 31).unwrap();
927
928			layout.set_date(&mut key1, 0, date1.clone());
929			layout.set_date(&mut key2, 0, date2.clone());
930			layout.set_date(&mut key3, 0, date3.clone());
931
932			assert!(key1.as_slice() < key2.as_slice());
933			assert!(key2.as_slice() < key3.as_slice());
934			assert_eq!(layout.get_date(&key1, 0), date1);
935			assert_eq!(layout.get_date(&key2, 0), date2);
936			assert_eq!(layout.get_date(&key3, 0), date3);
937		}
938
939		#[test]
940		fn test_desc() {
941			let layout = IndexShape::new(&[ValueType::Date], &[SortDirection::Desc]).unwrap();
942			let mut key1 = layout.allocate_key();
943			let mut key2 = layout.allocate_key();
944			let mut key3 = layout.allocate_key();
945
946			let date1 = Date::new(2020, 1, 1).unwrap();
947			let date2 = Date::new(2023, 6, 15).unwrap();
948			let date3 = Date::new(2025, 12, 31).unwrap();
949
950			layout.set_date(&mut key1, 0, date1.clone());
951			layout.set_date(&mut key2, 0, date2.clone());
952			layout.set_date(&mut key3, 0, date3.clone());
953
954			assert!(key1.as_slice() > key2.as_slice());
955			assert!(key2.as_slice() > key3.as_slice());
956			assert_eq!(layout.get_date(&key1, 0), date1);
957			assert_eq!(layout.get_date(&key2, 0), date2);
958			assert_eq!(layout.get_date(&key3, 0), date3);
959		}
960	}
961
962	mod row_number {
963		use reifydb_value::value::value_type::ValueType;
964
965		use crate::{sort::SortDirection, value::index::shape::IndexShape};
966
967		#[test]
968		fn test_asc() {
969			let layout = IndexShape::new(&[ValueType::Uint8], &[SortDirection::Asc]).unwrap();
970			let mut key1 = layout.allocate_key();
971			let mut key2 = layout.allocate_key();
972			let mut key3 = layout.allocate_key();
973
974			layout.set_row_number(&mut key1, 0, 1u64);
975			layout.set_row_number(&mut key2, 0, 1000u64);
976			layout.set_row_number(&mut key3, 0, u64::MAX);
977
978			assert!(key1.as_slice() < key2.as_slice());
979			assert!(key2.as_slice() < key3.as_slice());
980			assert_eq!(layout.get_row_number(&key1, 0), 1);
981			assert_eq!(layout.get_row_number(&key2, 0), 1000);
982			assert_eq!(layout.get_row_number(&key3, 0), u64::MAX);
983		}
984
985		#[test]
986		fn test_desc() {
987			let layout = IndexShape::new(&[ValueType::Uint8], &[SortDirection::Desc]).unwrap();
988			let mut key1 = layout.allocate_key();
989			let mut key2 = layout.allocate_key();
990			let mut key3 = layout.allocate_key();
991
992			layout.set_row_number(&mut key1, 0, 1u64);
993			layout.set_row_number(&mut key2, 0, 1000u64);
994			layout.set_row_number(&mut key3, 0, u64::MAX);
995
996			assert!(key1.as_slice() > key2.as_slice());
997			assert!(key2.as_slice() > key3.as_slice());
998			assert_eq!(layout.get_row_number(&key1, 0), 1);
999			assert_eq!(layout.get_row_number(&key2, 0), 1000);
1000			assert_eq!(layout.get_row_number(&key3, 0), u64::MAX);
1001		}
1002	}
1003
1004	mod identity_id {
1005		use reifydb_runtime::context::{
1006			clock::{Clock, MockClock},
1007			rng::Rng,
1008		};
1009		use reifydb_value::value::{identity::IdentityId, value_type::ValueType};
1010
1011		use crate::{sort::SortDirection, value::index::shape::IndexShape};
1012
1013		fn test_clock_and_rng() -> (MockClock, Clock, Rng) {
1014			let mock = MockClock::from_millis(1000);
1015			let clock = Clock::Mock(mock.clone());
1016			let rng = Rng::seeded(42);
1017			(mock, clock, rng)
1018		}
1019
1020		#[test]
1021		fn test_asc() {
1022			let (mock, clock, rng) = test_clock_and_rng();
1023			let layout = IndexShape::new(&[ValueType::IdentityId], &[SortDirection::Asc]).unwrap();
1024			let mut key1 = layout.allocate_key();
1025			let mut key2 = layout.allocate_key();
1026
1027			let id1 = IdentityId::generate(&clock, &rng);
1028			// Advance the clock so the two ids get different timestamps.
1029			mock.advance_millis(10);
1030			let id2 = IdentityId::generate(&clock, &rng);
1031
1032			layout.set_identity_id(&mut key1, 0, id1.clone());
1033			layout.set_identity_id(&mut key2, 0, id2.clone());
1034
1035			assert!(key1.as_slice() < key2.as_slice());
1036			assert_eq!(layout.get_identity_id(&key1, 0), id1);
1037			assert_eq!(layout.get_identity_id(&key2, 0), id2);
1038		}
1039
1040		#[test]
1041		fn test_desc() {
1042			let (mock, clock, rng) = test_clock_and_rng();
1043			let layout = IndexShape::new(&[ValueType::IdentityId], &[SortDirection::Desc]).unwrap();
1044			let mut key1 = layout.allocate_key();
1045			let mut key2 = layout.allocate_key();
1046
1047			let id1 = IdentityId::generate(&clock, &rng);
1048			// Advance the clock so the two ids get different timestamps.
1049			mock.advance_millis(10);
1050			let id2 = IdentityId::generate(&clock, &rng);
1051
1052			layout.set_identity_id(&mut key1, 0, id1.clone());
1053			layout.set_identity_id(&mut key2, 0, id2.clone());
1054
1055			assert!(key1.as_slice() > key2.as_slice());
1056			assert_eq!(layout.get_identity_id(&key1, 0), id1);
1057			assert_eq!(layout.get_identity_id(&key2, 0), id2);
1058		}
1059
1060		#[test]
1061		fn test_roundtrip() {
1062			let (_mock, clock, rng) = test_clock_and_rng();
1063			let layout = IndexShape::new(&[ValueType::IdentityId], &[SortDirection::Asc]).unwrap();
1064
1065			let id = IdentityId::generate(&clock, &rng);
1066			let mut key = layout.allocate_key();
1067
1068			layout.set_identity_id(&mut key, 0, id.clone());
1069			let retrieved = layout.get_identity_id(&key, 0);
1070			assert_eq!(retrieved, id);
1071		}
1072	}
1073
1074	mod composite {
1075		use reifydb_value::value::value_type::ValueType;
1076
1077		use crate::{sort::SortDirection, value::index::shape::IndexShape};
1078
1079		#[test]
1080		fn test_mixed_directions() {
1081			let layout = IndexShape::new(
1082				&[ValueType::Int4, ValueType::Uint8, ValueType::Uint8],
1083				&[SortDirection::Desc, SortDirection::Asc, SortDirection::Asc],
1084			)
1085			.unwrap();
1086
1087			let mut key1 = layout.allocate_key();
1088			let mut key2 = layout.allocate_key();
1089			let mut key3 = layout.allocate_key();
1090			let mut key4 = layout.allocate_key();
1091
1092			layout.set_i32(&mut key1, 0, 100i32);
1093			layout.set_u64(&mut key1, 1, 1u64);
1094			layout.set_row_number(&mut key1, 2, 1u64);
1095
1096			layout.set_i32(&mut key2, 0, 100i32);
1097			layout.set_u64(&mut key2, 1, 2u64);
1098			layout.set_row_number(&mut key2, 2, 1u64);
1099
1100			layout.set_i32(&mut key3, 0, 50i32);
1101			layout.set_u64(&mut key3, 1, 1u64);
1102			layout.set_row_number(&mut key3, 2, 1u64);
1103
1104			layout.set_i32(&mut key4, 0, 50i32);
1105			layout.set_u64(&mut key4, 1, 1u64);
1106			layout.set_row_number(&mut key4, 2, 2u64);
1107
1108			// (100,1,1) vs (100,2,1): tie on the first field, second field ascending.
1109			assert!(key1.as_slice() < key2.as_slice());
1110			// (100,1,1) vs (50,1,1): the first field is DESC, so 100 sorts below 50 in byte order.
1111			assert!(key1.as_slice() < key3.as_slice());
1112			// (50,1,1) vs (50,1,2): tie on the first two fields, third field ascending.
1113			assert!(key3.as_slice() < key4.as_slice());
1114		}
1115	}
1116}