Skip to main content

reifydb_core/value/index/
set.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later
2// Copyright (c) 2026 ReifyDB
3
4use std::{f64, ptr};
5
6use reifydb_value::value::{
7	date::Date,
8	datetime::DateTime,
9	duration::Duration,
10	identity::IdentityId,
11	time::Time,
12	uuid::{Uuid4, Uuid7},
13	value_type::ValueType,
14};
15use uuid::Uuid;
16
17use crate::{
18	sort::SortDirection,
19	value::index::{encoded::EncodedIndexKey, shape::IndexShape},
20};
21
22impl IndexShape {
23	pub fn set_bool(&self, key: &mut EncodedIndexKey, index: usize, value: impl Into<bool>) {
24		let field = &self.fields[index];
25		debug_assert_eq!(field.value, ValueType::Boolean);
26		key.set_valid(index, true);
27
28		let byte_value = match field.direction {
29			SortDirection::Asc => {
30				if value.into() {
31					1u8
32				} else {
33					0u8
34				}
35			}
36			SortDirection::Desc => {
37				if value.into() {
38					0u8
39				} else {
40					1u8
41				}
42			}
43		};
44
45		unsafe { ptr::write_unaligned(key.make_mut().as_mut_ptr().add(field.offset), byte_value) }
46	}
47
48	pub fn set_f32(&self, key: &mut EncodedIndexKey, index: usize, value: impl Into<f32>) {
49		let field = &self.fields[index];
50		debug_assert_eq!(field.value, ValueType::Float4);
51		key.set_valid(index, true);
52
53		let v = value.into();
54		let mut bytes = v.to_bits().to_be_bytes();
55
56		if v.is_sign_negative() {
57			for b in bytes.iter_mut() {
58				*b = !*b;
59			}
60		} else {
61			bytes[0] ^= 0x80;
62		}
63
64		if field.direction == SortDirection::Desc {
65			for b in bytes.iter_mut() {
66				*b = !*b;
67			}
68		}
69
70		unsafe {
71			ptr::copy_nonoverlapping(bytes.as_ptr(), key.make_mut().as_mut_ptr().add(field.offset), 4);
72		}
73	}
74
75	pub fn set_f64(&self, key: &mut EncodedIndexKey, index: usize, value: impl Into<f64>) {
76		let field = &self.fields[index];
77		debug_assert_eq!(field.value, ValueType::Float8);
78		key.set_valid(index, true);
79
80		let v = value.into();
81		let mut bytes = v.to_bits().to_be_bytes();
82
83		if v.is_sign_negative() {
84			for b in bytes.iter_mut() {
85				*b = !*b;
86			}
87		} else {
88			bytes[0] ^= 0x80;
89		}
90
91		if field.direction == SortDirection::Desc {
92			for b in bytes.iter_mut() {
93				*b = !*b;
94			}
95		}
96
97		unsafe {
98			ptr::copy_nonoverlapping(bytes.as_ptr(), key.make_mut().as_mut_ptr().add(field.offset), 8);
99		}
100	}
101
102	pub fn set_i8(&self, key: &mut EncodedIndexKey, index: usize, value: impl Into<i8>) {
103		let field = &self.fields[index];
104		debug_assert_eq!(field.value, ValueType::Int1);
105		key.set_valid(index, true);
106
107		let mut bytes = value.into().to_be_bytes();
108
109		match field.direction {
110			SortDirection::Asc => {
111				bytes[0] ^= 0x80;
112			}
113			SortDirection::Desc => {
114				bytes[0] ^= 0x80;
115				for b in bytes.iter_mut() {
116					*b = !*b;
117				}
118			}
119		}
120
121		unsafe { ptr::write_unaligned(key.make_mut().as_mut_ptr().add(field.offset), bytes[0]) }
122	}
123
124	pub fn set_i16(&self, key: &mut EncodedIndexKey, index: usize, value: impl Into<i16>) {
125		let field = &self.fields[index];
126		debug_assert_eq!(field.value, ValueType::Int2);
127		key.set_valid(index, true);
128
129		let mut bytes = value.into().to_be_bytes();
130
131		match field.direction {
132			SortDirection::Asc => {
133				bytes[0] ^= 0x80;
134			}
135			SortDirection::Desc => {
136				bytes[0] ^= 0x80;
137				for b in bytes.iter_mut() {
138					*b = !*b;
139				}
140			}
141		}
142
143		unsafe {
144			ptr::copy_nonoverlapping(bytes.as_ptr(), key.make_mut().as_mut_ptr().add(field.offset), 2);
145		}
146	}
147
148	pub fn set_i32(&self, key: &mut EncodedIndexKey, index: usize, value: impl Into<i32>) {
149		let field = &self.fields[index];
150		debug_assert_eq!(field.value, ValueType::Int4);
151		key.set_valid(index, true);
152
153		let mut bytes = value.into().to_be_bytes();
154
155		match field.direction {
156			SortDirection::Asc => {
157				bytes[0] ^= 0x80;
158			}
159			SortDirection::Desc => {
160				bytes[0] ^= 0x80;
161				for b in bytes.iter_mut() {
162					*b = !*b;
163				}
164			}
165		}
166
167		unsafe {
168			ptr::copy_nonoverlapping(bytes.as_ptr(), key.make_mut().as_mut_ptr().add(field.offset), 4);
169		}
170	}
171
172	pub fn set_i64(&self, key: &mut EncodedIndexKey, index: usize, value: impl Into<i64>) {
173		let field = &self.fields[index];
174		debug_assert_eq!(field.value, ValueType::Int8);
175		key.set_valid(index, true);
176
177		let mut bytes = value.into().to_be_bytes();
178
179		match field.direction {
180			SortDirection::Asc => {
181				bytes[0] ^= 0x80;
182			}
183			SortDirection::Desc => {
184				bytes[0] ^= 0x80;
185				for b in bytes.iter_mut() {
186					*b = !*b;
187				}
188			}
189		}
190
191		unsafe {
192			ptr::copy_nonoverlapping(bytes.as_ptr(), key.make_mut().as_mut_ptr().add(field.offset), 8);
193		}
194	}
195
196	pub fn set_i128(&self, key: &mut EncodedIndexKey, index: usize, value: impl Into<i128>) {
197		let field = &self.fields[index];
198		debug_assert_eq!(field.value, ValueType::Int16);
199		key.set_valid(index, true);
200
201		let mut bytes = value.into().to_be_bytes();
202
203		match field.direction {
204			SortDirection::Asc => {
205				bytes[0] ^= 0x80;
206			}
207			SortDirection::Desc => {
208				bytes[0] ^= 0x80;
209				for b in bytes.iter_mut() {
210					*b = !*b;
211				}
212			}
213		}
214
215		unsafe {
216			ptr::copy_nonoverlapping(bytes.as_ptr(), key.make_mut().as_mut_ptr().add(field.offset), 16);
217		}
218	}
219
220	pub fn set_u8(&self, key: &mut EncodedIndexKey, index: usize, value: impl Into<u8>) {
221		let field = &self.fields[index];
222		debug_assert_eq!(field.value, ValueType::Uint1);
223		key.set_valid(index, true);
224
225		let byte = match field.direction {
226			SortDirection::Asc => value.into(),
227			SortDirection::Desc => !value.into(),
228		};
229
230		unsafe { ptr::write_unaligned(key.make_mut().as_mut_ptr().add(field.offset), byte) }
231	}
232
233	pub fn set_u16(&self, key: &mut EncodedIndexKey, index: usize, value: impl Into<u16>) {
234		let field = &self.fields[index];
235		debug_assert_eq!(field.value, ValueType::Uint2);
236		key.set_valid(index, true);
237
238		let bytes = match field.direction {
239			SortDirection::Asc => value.into().to_be_bytes(),
240			SortDirection::Desc => (!value.into()).to_be_bytes(),
241		};
242
243		unsafe {
244			ptr::copy_nonoverlapping(bytes.as_ptr(), key.make_mut().as_mut_ptr().add(field.offset), 2);
245		}
246	}
247
248	pub fn set_u32(&self, key: &mut EncodedIndexKey, index: usize, value: impl Into<u32>) {
249		let field = &self.fields[index];
250		debug_assert_eq!(field.value, ValueType::Uint4);
251		key.set_valid(index, true);
252
253		let bytes = match field.direction {
254			SortDirection::Asc => value.into().to_be_bytes(),
255			SortDirection::Desc => (!value.into()).to_be_bytes(),
256		};
257
258		unsafe {
259			ptr::copy_nonoverlapping(bytes.as_ptr(), key.make_mut().as_mut_ptr().add(field.offset), 4);
260		}
261	}
262
263	pub fn set_u64(&self, key: &mut EncodedIndexKey, index: usize, value: impl Into<u64>) {
264		let field = &self.fields[index];
265		debug_assert_eq!(field.value, ValueType::Uint8);
266		key.set_valid(index, true);
267
268		let bytes = match field.direction {
269			SortDirection::Asc => value.into().to_be_bytes(),
270			SortDirection::Desc => (!value.into()).to_be_bytes(),
271		};
272
273		unsafe {
274			ptr::copy_nonoverlapping(bytes.as_ptr(), key.make_mut().as_mut_ptr().add(field.offset), 8);
275		}
276	}
277
278	pub fn set_u128(&self, key: &mut EncodedIndexKey, index: usize, value: impl Into<u128>) {
279		let field = &self.fields[index];
280		debug_assert_eq!(field.value, ValueType::Uint16);
281		key.set_valid(index, true);
282
283		let bytes = match field.direction {
284			SortDirection::Asc => value.into().to_be_bytes(),
285			SortDirection::Desc => (!value.into()).to_be_bytes(),
286		};
287
288		unsafe {
289			ptr::copy_nonoverlapping(bytes.as_ptr(), key.make_mut().as_mut_ptr().add(field.offset), 16);
290		}
291	}
292
293	pub fn set_row_number(&self, key: &mut EncodedIndexKey, index: usize, value: impl Into<u64>) {
294		let field = &self.fields[index];
295		debug_assert_eq!(field.value, ValueType::Uint8);
296		key.set_valid(index, true);
297
298		let bytes = match field.direction {
299			SortDirection::Asc => value.into().to_be_bytes(),
300			SortDirection::Desc => (!value.into()).to_be_bytes(),
301		};
302
303		unsafe {
304			ptr::copy_nonoverlapping(bytes.as_ptr(), key.make_mut().as_mut_ptr().add(field.offset), 8);
305		}
306	}
307
308	pub fn set_date(&self, key: &mut EncodedIndexKey, index: usize, value: Date) {
309		let field = &self.fields[index];
310		debug_assert_eq!(field.value, ValueType::Date);
311		key.set_valid(index, true);
312
313		let days = value.to_days_since_epoch();
314		let mut bytes = days.to_be_bytes();
315
316		match field.direction {
317			SortDirection::Asc => {
318				bytes[0] ^= 0x80;
319			}
320			SortDirection::Desc => {
321				bytes[0] ^= 0x80;
322				for b in bytes.iter_mut() {
323					*b = !*b;
324				}
325			}
326		}
327
328		unsafe {
329			ptr::copy_nonoverlapping(bytes.as_ptr(), key.make_mut().as_mut_ptr().add(field.offset), 4);
330		}
331	}
332
333	pub fn set_datetime(&self, key: &mut EncodedIndexKey, index: usize, value: DateTime) {
334		let field = &self.fields[index];
335		debug_assert_eq!(field.value, ValueType::DateTime);
336		key.set_valid(index, true);
337
338		let nanos = value.to_nanos();
339		let bytes = match field.direction {
340			SortDirection::Asc => nanos.to_be_bytes(),
341			SortDirection::Desc => (!nanos).to_be_bytes(),
342		};
343
344		unsafe {
345			ptr::copy_nonoverlapping(bytes.as_ptr(), key.make_mut().as_mut_ptr().add(field.offset), 8);
346		}
347	}
348
349	pub fn set_time(&self, key: &mut EncodedIndexKey, index: usize, value: Time) {
350		let field = &self.fields[index];
351		debug_assert_eq!(field.value, ValueType::Time);
352		key.set_valid(index, true);
353
354		let nanos = value.to_nanos_since_midnight();
355		let bytes = match field.direction {
356			SortDirection::Asc => nanos.to_be_bytes(),
357			SortDirection::Desc => (!nanos).to_be_bytes(),
358		};
359
360		unsafe {
361			ptr::copy_nonoverlapping(bytes.as_ptr(), key.make_mut().as_mut_ptr().add(field.offset), 8);
362		}
363	}
364
365	pub fn set_duration(&self, key: &mut EncodedIndexKey, index: usize, value: Duration) {
366		let field = &self.fields[index];
367		debug_assert_eq!(field.value, ValueType::Duration);
368		key.set_valid(index, true);
369
370		let mut months_bytes = value.get_months().to_be_bytes();
371		let mut days_bytes = value.get_days().to_be_bytes();
372		let mut nanos_bytes = value.get_nanos().to_be_bytes();
373
374		match field.direction {
375			SortDirection::Asc => {
376				months_bytes[0] ^= 0x80;
377				days_bytes[0] ^= 0x80;
378				nanos_bytes[0] ^= 0x80;
379			}
380			SortDirection::Desc => {
381				months_bytes[0] ^= 0x80;
382				days_bytes[0] ^= 0x80;
383				nanos_bytes[0] ^= 0x80;
384				for b in months_bytes.iter_mut() {
385					*b = !*b;
386				}
387				for b in days_bytes.iter_mut() {
388					*b = !*b;
389				}
390				for b in nanos_bytes.iter_mut() {
391					*b = !*b;
392				}
393			}
394		}
395
396		unsafe {
397			ptr::copy_nonoverlapping(
398				months_bytes.as_ptr(),
399				key.make_mut().as_mut_ptr().add(field.offset),
400				4,
401			);
402			ptr::copy_nonoverlapping(
403				days_bytes.as_ptr(),
404				key.make_mut().as_mut_ptr().add(field.offset + 4),
405				4,
406			);
407			ptr::copy_nonoverlapping(
408				nanos_bytes.as_ptr(),
409				key.make_mut().as_mut_ptr().add(field.offset + 8),
410				8,
411			);
412		}
413	}
414
415	pub fn set_uuid4(&self, key: &mut EncodedIndexKey, index: usize, value: Uuid4) {
416		let field = &self.fields[index];
417		debug_assert_eq!(field.value, ValueType::Uuid4);
418		key.set_valid(index, true);
419
420		let uuid: Uuid = value.into();
421		let uuid_bytes = uuid.as_bytes();
422		let mut bytes = [0u8; 16];
423		bytes.copy_from_slice(uuid_bytes);
424
425		if field.direction == SortDirection::Desc {
426			for b in bytes.iter_mut() {
427				*b = !*b;
428			}
429		}
430
431		unsafe {
432			ptr::copy_nonoverlapping(bytes.as_ptr(), key.make_mut().as_mut_ptr().add(field.offset), 16);
433		}
434	}
435
436	pub fn set_uuid7(&self, key: &mut EncodedIndexKey, index: usize, value: Uuid7) {
437		let field = &self.fields[index];
438		debug_assert_eq!(field.value, ValueType::Uuid7);
439		key.set_valid(index, true);
440
441		let uuid: Uuid = value.into();
442		let uuid_bytes = uuid.as_bytes();
443		let mut bytes = [0u8; 16];
444		bytes.copy_from_slice(uuid_bytes);
445
446		if field.direction == SortDirection::Desc {
447			for b in bytes.iter_mut() {
448				*b = !*b;
449			}
450		}
451
452		unsafe {
453			ptr::copy_nonoverlapping(bytes.as_ptr(), key.make_mut().as_mut_ptr().add(field.offset), 16);
454		}
455	}
456
457	pub fn set_identity_id(&self, key: &mut EncodedIndexKey, index: usize, value: IdentityId) {
458		let field = &self.fields[index];
459		debug_assert_eq!(field.value, ValueType::IdentityId);
460		key.set_valid(index, true);
461
462		let uuid: Uuid = value.0.into();
463		let uuid_bytes = uuid.as_bytes();
464		let mut bytes = [0u8; 16];
465		bytes.copy_from_slice(uuid_bytes);
466
467		if field.direction == SortDirection::Desc {
468			for b in bytes.iter_mut() {
469				*b = !*b;
470			}
471		}
472
473		unsafe {
474			ptr::copy_nonoverlapping(bytes.as_ptr(), key.make_mut().as_mut_ptr().add(field.offset), 16);
475		}
476	}
477
478	pub fn set_none(&self, key: &mut EncodedIndexKey, index: usize) {
479		let field = &self.fields[index];
480		key.set_valid(index, false);
481
482		let buf = key.make_mut();
483		let start = field.offset;
484		let end = start + field.size;
485		buf[start..end].fill(0);
486	}
487}
488
489#[cfg(test)]
490pub mod tests {
491	use crate::{sort::SortDirection, value::index::shape::IndexShape};
492
493	mod bool {
494		use reifydb_value::value::value_type::ValueType;
495
496		use super::*;
497
498		#[test]
499		fn test_asc() {
500			let layout = IndexShape::new(&[ValueType::Boolean], &[SortDirection::Asc]).unwrap();
501			let mut key_false = layout.allocate_key();
502			let mut key_true = layout.allocate_key();
503
504			layout.set_bool(&mut key_false, 0, false);
505			layout.set_bool(&mut key_true, 0, true);
506
507			// Check bitvec shows field is set
508			assert_eq!(key_false[0] & 0x01, 0x01);
509			assert_eq!(key_true[0] & 0x01, 0x01);
510
511			// Check values at field offset (after bitvec)
512			let offset = layout.fields[0].offset;
513			assert_eq!(key_false[offset], 0);
514			assert_eq!(key_true[offset], 1);
515
516			// Verify ordering
517			assert!(key_false.as_slice() < key_true.as_slice());
518		}
519
520		#[test]
521		fn test_desc() {
522			let layout = IndexShape::new(&[ValueType::Boolean], &[SortDirection::Desc]).unwrap();
523			let mut key_false = layout.allocate_key();
524			let mut key_true = layout.allocate_key();
525
526			layout.set_bool(&mut key_false, 0, false);
527			layout.set_bool(&mut key_true, 0, true);
528
529			// Check values at field offset (inverted for DESC)
530			let offset = layout.fields[0].offset;
531			assert_eq!(key_false[offset], 1); // false becomes 1 in DESC
532			assert_eq!(key_true[offset], 0); // true becomes 0 in DESC
533
534			// Verify ordering (reversed)
535			assert!(key_false.as_slice() > key_true.as_slice());
536		}
537	}
538
539	mod i8 {
540		use reifydb_value::value::value_type::ValueType;
541
542		use crate::{sort::SortDirection, value::index::shape::IndexShape};
543
544		#[test]
545		fn test_asc() {
546			let layout = IndexShape::new(&[ValueType::Int1], &[SortDirection::Asc]).unwrap();
547			let mut key_neg = layout.allocate_key();
548			let mut key_zero = layout.allocate_key();
549			let mut key_pos = layout.allocate_key();
550
551			layout.set_i8(&mut key_neg, 0, -128i8);
552			layout.set_i8(&mut key_zero, 0, 0i8);
553			layout.set_i8(&mut key_pos, 0, 127i8);
554
555			let offset = layout.fields[0].offset;
556			// -128 with sign bit flipped: 0x80 -> 0x00
557			assert_eq!(key_neg[offset], 0x00);
558			// 0 with sign bit flipped: 0x00 -> 0x80
559			assert_eq!(key_zero[offset], 0x80);
560			// 127 with sign bit flipped: 0x7F -> 0xFF
561			assert_eq!(key_pos[offset], 0xFF);
562
563			// Verify ordering
564			assert!(key_neg.as_slice() < key_zero.as_slice());
565			assert!(key_zero.as_slice() < key_pos.as_slice());
566		}
567
568		#[test]
569		fn test_desc() {
570			let layout = IndexShape::new(&[ValueType::Int1], &[SortDirection::Desc]).unwrap();
571			let mut key_neg = layout.allocate_key();
572			let mut key_zero = layout.allocate_key();
573			let mut key_pos = layout.allocate_key();
574
575			layout.set_i8(&mut key_neg, 0, -128i8);
576			layout.set_i8(&mut key_zero, 0, 0i8);
577			layout.set_i8(&mut key_pos, 0, 127i8);
578
579			let offset = layout.fields[0].offset;
580			// -128: 0x80 -> flip sign: 0x00 -> invert: 0xFF
581			assert_eq!(key_neg[offset], 0xFF);
582			// 0: 0x00 -> flip sign: 0x80 -> invert: 0x7F
583			assert_eq!(key_zero[offset], 0x7F);
584			// 127: 0x7F -> flip sign: 0xFF -> invert: 0x00
585			assert_eq!(key_pos[offset], 0x00);
586
587			// Verify ordering (reversed)
588			assert!(key_neg.as_slice() > key_zero.as_slice());
589			assert!(key_zero.as_slice() > key_pos.as_slice());
590		}
591	}
592
593	mod i32 {
594		use reifydb_value::value::value_type::ValueType;
595
596		use crate::{sort::SortDirection, value::index::shape::IndexShape};
597
598		#[test]
599		fn test_asc() {
600			let layout = IndexShape::new(&[ValueType::Int4], &[SortDirection::Asc]).unwrap();
601			let mut key_neg = layout.allocate_key();
602			let mut key_zero = layout.allocate_key();
603			let mut key_pos = layout.allocate_key();
604
605			layout.set_i32(&mut key_neg, 0, i32::MIN);
606			layout.set_i32(&mut key_zero, 0, 0i32);
607			layout.set_i32(&mut key_pos, 0, i32::MAX);
608
609			let offset = layout.fields[0].offset;
610			// i32::MIN in big-endian with sign bit flipped
611			assert_eq!(&key_neg[offset..offset + 4], &[0x00, 0x00, 0x00, 0x00]);
612			// 0 with sign bit flipped
613			assert_eq!(&key_zero[offset..offset + 4], &[0x80, 0x00, 0x00, 0x00]);
614			// i32::MAX with sign bit flipped
615			assert_eq!(&key_pos[offset..offset + 4], &[0xFF, 0xFF, 0xFF, 0xFF]);
616
617			// Verify ordering
618			assert!(key_neg.as_slice() < key_zero.as_slice());
619			assert!(key_zero.as_slice() < key_pos.as_slice());
620		}
621
622		#[test]
623		fn test_desc() {
624			let layout = IndexShape::new(&[ValueType::Int4], &[SortDirection::Desc]).unwrap();
625			let mut key_neg = layout.allocate_key();
626			let mut key_zero = layout.allocate_key();
627			let mut key_pos = layout.allocate_key();
628
629			layout.set_i32(&mut key_neg, 0, i32::MIN);
630			layout.set_i32(&mut key_zero, 0, 0i32);
631			layout.set_i32(&mut key_pos, 0, i32::MAX);
632
633			let offset = layout.fields[0].offset;
634			// i32::MIN: flip sign then invert all
635			assert_eq!(&key_neg[offset..offset + 4], &[0xFF, 0xFF, 0xFF, 0xFF]);
636			// 0: flip sign then invert all
637			assert_eq!(&key_zero[offset..offset + 4], &[0x7F, 0xFF, 0xFF, 0xFF]);
638			// i32::MAX: flip sign then invert all
639			assert_eq!(&key_pos[offset..offset + 4], &[0x00, 0x00, 0x00, 0x00]);
640
641			// Verify ordering (reversed)
642			assert!(key_neg.as_slice() > key_zero.as_slice());
643			assert!(key_zero.as_slice() > key_pos.as_slice());
644		}
645	}
646
647	mod i64 {
648		use reifydb_value::value::value_type::ValueType;
649
650		use crate::{sort::SortDirection, value::index::shape::IndexShape};
651
652		#[test]
653		fn test_asc() {
654			let layout = IndexShape::new(&[ValueType::Int8], &[SortDirection::Asc]).unwrap();
655			let mut key = layout.allocate_key();
656
657			layout.set_i64(&mut key, 0, -1i64);
658
659			let offset = layout.fields[0].offset;
660			// -1 in two's complement is all 1s, with sign bit
661			// flipped becomes 0x7F...
662			assert_eq!(&key[offset..offset + 8], &[0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]);
663		}
664
665		#[test]
666		fn test_desc() {
667			let layout = IndexShape::new(&[ValueType::Int8], &[SortDirection::Desc]).unwrap();
668			let mut key = layout.allocate_key();
669
670			layout.set_i64(&mut key, 0, -1i64);
671
672			let offset = layout.fields[0].offset;
673			// -1: flip sign then invert all
674			assert_eq!(&key[offset..offset + 8], &[0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
675		}
676	}
677
678	mod u8 {
679		use reifydb_value::value::value_type::ValueType;
680
681		use crate::{sort::SortDirection, value::index::shape::IndexShape};
682
683		#[test]
684		fn test_asc() {
685			let layout = IndexShape::new(&[ValueType::Uint1], &[SortDirection::Asc]).unwrap();
686			let mut key_min = layout.allocate_key();
687			let mut key_mid = layout.allocate_key();
688			let mut key_max = layout.allocate_key();
689
690			layout.set_u8(&mut key_min, 0, 0u8);
691			layout.set_u8(&mut key_mid, 0, 128u8);
692			layout.set_u8(&mut key_max, 0, 255u8);
693
694			let offset = layout.fields[0].offset;
695			assert_eq!(key_min[offset], 0x00);
696			assert_eq!(key_mid[offset], 0x80);
697			assert_eq!(key_max[offset], 0xFF);
698
699			// Verify ordering
700			assert!(key_min.as_slice() < key_mid.as_slice());
701			assert!(key_mid.as_slice() < key_max.as_slice());
702		}
703
704		#[test]
705		fn test_desc() {
706			let layout = IndexShape::new(&[ValueType::Uint1], &[SortDirection::Desc]).unwrap();
707			let mut key_min = layout.allocate_key();
708			let mut key_mid = layout.allocate_key();
709			let mut key_max = layout.allocate_key();
710
711			layout.set_u8(&mut key_min, 0, 0u8);
712			layout.set_u8(&mut key_mid, 0, 128u8);
713			layout.set_u8(&mut key_max, 0, 255u8);
714
715			let offset = layout.fields[0].offset;
716			// Inverted for DESC
717			assert_eq!(key_min[offset], 0xFF);
718			assert_eq!(key_mid[offset], 0x7F);
719			assert_eq!(key_max[offset], 0x00);
720
721			// Verify ordering (reversed)
722			assert!(key_min.as_slice() > key_mid.as_slice());
723			assert!(key_mid.as_slice() > key_max.as_slice());
724		}
725	}
726
727	mod u32 {
728		use reifydb_value::value::value_type::ValueType;
729
730		use crate::{sort::SortDirection, value::index::shape::IndexShape};
731
732		#[test]
733		fn test_asc() {
734			let layout = IndexShape::new(&[ValueType::Uint4], &[SortDirection::Asc]).unwrap();
735			let mut key = layout.allocate_key();
736
737			layout.set_u32(&mut key, 0, 0x12345678u32);
738
739			let offset = layout.fields[0].offset;
740			// Big-endian representation
741			assert_eq!(&key[offset..offset + 4], &[0x12, 0x34, 0x56, 0x78]);
742		}
743
744		#[test]
745		fn test_desc() {
746			let layout = IndexShape::new(&[ValueType::Uint4], &[SortDirection::Desc]).unwrap();
747			let mut key = layout.allocate_key();
748
749			layout.set_u32(&mut key, 0, 0x12345678u32);
750
751			let offset = layout.fields[0].offset;
752			// Inverted for DESC
753			assert_eq!(&key[offset..offset + 4], &[0xED, 0xCB, 0xA9, 0x87]);
754		}
755	}
756
757	mod u64 {
758		use reifydb_value::value::value_type::ValueType;
759
760		use crate::{sort::SortDirection, value::index::shape::IndexShape};
761
762		#[test]
763		fn test_asc() {
764			let layout = IndexShape::new(&[ValueType::Uint8], &[SortDirection::Asc]).unwrap();
765			let mut key = layout.allocate_key();
766
767			layout.set_u64(&mut key, 0, u64::MAX);
768
769			let offset = layout.fields[0].offset;
770			assert_eq!(&key[offset..offset + 8], &[0xFF; 8]);
771		}
772
773		#[test]
774		fn test_desc() {
775			let layout = IndexShape::new(&[ValueType::Uint8], &[SortDirection::Desc]).unwrap();
776			let mut key = layout.allocate_key();
777
778			layout.set_u64(&mut key, 0, u64::MAX);
779
780			let offset = layout.fields[0].offset;
781			assert_eq!(&key[offset..offset + 8], &[0x00; 8]);
782		}
783	}
784
785	mod f32 {
786		use reifydb_value::value::value_type::ValueType;
787
788		use crate::{sort::SortDirection, value::index::shape::IndexShape};
789
790		#[test]
791		fn test_asc() {
792			let layout = IndexShape::new(&[ValueType::Float4], &[SortDirection::Asc]).unwrap();
793			let mut key_neg = layout.allocate_key();
794			let mut key_zero = layout.allocate_key();
795			let mut key_pos = layout.allocate_key();
796
797			layout.set_f32(&mut key_neg, 0, -1.0f32);
798			layout.set_f32(&mut key_zero, 0, 0.0f32);
799			layout.set_f32(&mut key_pos, 0, 1.0f32);
800
801			let offset = layout.fields[0].offset;
802
803			// -1.0f32: 0xBF800000 -> invert all: 0x407FFFFF
804			assert_eq!(&key_neg[offset..offset + 4], &[0x40, 0x7F, 0xFF, 0xFF]);
805			// 0.0f32: 0x00000000 -> flip sign: 0x80000000
806			assert_eq!(&key_zero[offset..offset + 4], &[0x80, 0x00, 0x00, 0x00]);
807			// 1.0f32: 0x3F800000 -> flip sign: 0xBF800000
808			assert_eq!(&key_pos[offset..offset + 4], &[0xBF, 0x80, 0x00, 0x00]);
809
810			// Verify ordering
811			assert!(key_neg.as_slice() < key_zero.as_slice());
812			assert!(key_zero.as_slice() < key_pos.as_slice());
813		}
814
815		#[test]
816		fn test_desc() {
817			let layout = IndexShape::new(&[ValueType::Float4], &[SortDirection::Desc]).unwrap();
818			let mut key_neg = layout.allocate_key();
819			let mut key_pos = layout.allocate_key();
820
821			layout.set_f32(&mut key_neg, 0, -1.0f32);
822			layout.set_f32(&mut key_pos, 0, 1.0f32);
823
824			let offset = layout.fields[0].offset;
825
826			// -1.0f32: ASC encoding then invert for DESC
827			assert_eq!(&key_neg[offset..offset + 4], &[0xBF, 0x80, 0x00, 0x00]);
828			// 1.0f32: ASC encoding then invert for DESC
829			assert_eq!(&key_pos[offset..offset + 4], &[0x40, 0x7F, 0xFF, 0xFF]);
830
831			// Verify ordering (reversed)
832			assert!(key_neg.as_slice() > key_pos.as_slice());
833		}
834	}
835
836	mod f64 {
837		use std::f64::consts::PI;
838
839		use reifydb_value::value::value_type::ValueType;
840
841		use crate::{sort::SortDirection, value::index::shape::IndexShape};
842
843		#[test]
844		fn test_asc() {
845			let layout = IndexShape::new(&[ValueType::Float8], &[SortDirection::Asc]).unwrap();
846			let mut key = layout.allocate_key();
847
848			layout.set_f64(&mut key, 0, PI);
849
850			let offset = layout.fields[0].offset;
851			// PI in IEEE 754: 0x400921FB54442D18 -> flip sign bit
852			assert_eq!(&key[offset..offset + 8], &[0xC0, 0x09, 0x21, 0xFB, 0x54, 0x44, 0x2D, 0x18]);
853		}
854
855		#[test]
856		fn test_desc() {
857			let layout = IndexShape::new(&[ValueType::Float8], &[SortDirection::Desc]).unwrap();
858			let mut key = layout.allocate_key();
859
860			layout.set_f64(&mut key, 0, PI);
861
862			let offset = layout.fields[0].offset;
863			// PI: ASC encoding then invert for DESC
864			assert_eq!(&key[offset..offset + 8], &[0x3F, 0xF6, 0xDE, 0x04, 0xAB, 0xBB, 0xD2, 0xE7]);
865		}
866	}
867
868	mod row_number {
869		use reifydb_value::value::value_type::ValueType;
870
871		use crate::{sort::SortDirection, value::index::shape::IndexShape};
872
873		#[test]
874		fn test_asc() {
875			let layout = IndexShape::new(&[ValueType::Uint8], &[SortDirection::Asc]).unwrap();
876			let mut key = layout.allocate_key();
877
878			layout.set_row_number(&mut key, 0, 0x123456789ABCDEFu64);
879
880			let offset = layout.fields[0].offset;
881			assert_eq!(&key[offset..offset + 8], &[0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF]);
882		}
883
884		#[test]
885		fn test_desc() {
886			let layout = IndexShape::new(&[ValueType::Uint8], &[SortDirection::Desc]).unwrap();
887			let mut key = layout.allocate_key();
888
889			layout.set_row_number(&mut key, 0, 0x123456789ABCDEFu64);
890
891			let offset = layout.fields[0].offset;
892			// Inverted for DESC
893			assert_eq!(&key[offset..offset + 8], &[0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10]);
894		}
895	}
896
897	mod date {
898		use reifydb_value::value::{date::Date, value_type::ValueType};
899
900		use crate::{sort::SortDirection, value::index::shape::IndexShape};
901
902		#[test]
903		fn test_asc() {
904			let layout = IndexShape::new(&[ValueType::Date], &[SortDirection::Asc]).unwrap();
905			let mut key = layout.allocate_key();
906
907			let date = Date::new(2025, 1, 1).unwrap();
908			layout.set_date(&mut key, 0, date);
909
910			let offset = layout.fields[0].offset;
911			// Date is stored as i32 days since epoch with sign bit
912			// flipped
913			let bytes = &key[offset..offset + 4];
914
915			// Verify it's properly encoded
916			let mut expected = date.to_days_since_epoch().to_be_bytes();
917			expected[0] ^= 0x80;
918			assert_eq!(bytes, expected);
919		}
920
921		#[test]
922		fn test_desc() {
923			let layout = IndexShape::new(&[ValueType::Date], &[SortDirection::Desc]).unwrap();
924			let mut key = layout.allocate_key();
925
926			let date = Date::new(2025, 1, 1).unwrap();
927			layout.set_date(&mut key, 0, date);
928
929			let offset = layout.fields[0].offset;
930			let bytes = &key[offset..offset + 4];
931
932			// Date with sign bit flipped then all inverted for DESC
933			let mut expected = date.to_days_since_epoch().to_be_bytes();
934			expected[0] ^= 0x80;
935			for b in expected.iter_mut() {
936				*b = !*b;
937			}
938			assert_eq!(bytes, expected);
939		}
940	}
941
942	mod composite {
943		use reifydb_value::value::value_type::ValueType;
944
945		use crate::{sort::SortDirection, value::index::shape::IndexShape};
946
947		#[test]
948		fn test_mixed_directions() {
949			let layout = IndexShape::new(
950				&[ValueType::Int4, ValueType::Uint8],
951				&[SortDirection::Desc, SortDirection::Asc],
952			)
953			.unwrap();
954
955			let mut key = layout.allocate_key();
956			layout.set_i32(&mut key, 0, 100);
957			layout.set_u64(&mut key, 1, 200u64);
958
959			// Check first field (i32 DESC)
960			let offset1 = layout.fields[0].offset;
961			let mut expected_i32 = 100i32.to_be_bytes();
962			expected_i32[0] ^= 0x80;
963			for b in expected_i32.iter_mut() {
964				*b = !*b;
965			}
966			assert_eq!(&key[offset1..offset1 + 4], expected_i32);
967
968			// Check second field (u64 ASC)
969			let offset2 = layout.fields[1].offset;
970			let expected_u64 = 200u64.to_be_bytes();
971			assert_eq!(&key[offset2..offset2 + 8], expected_u64);
972		}
973	}
974
975	mod uuid4 {
976		use reifydb_value::value::{uuid::Uuid4, value_type::ValueType};
977
978		use crate::{sort::SortDirection, value::index::shape::IndexShape};
979
980		#[test]
981		fn test_asc() {
982			let layout = IndexShape::new(&[ValueType::Uuid4], &[SortDirection::Asc]).unwrap();
983			let mut key1 = layout.allocate_key();
984			let mut key2 = layout.allocate_key();
985
986			let uuid1 = Uuid4::generate();
987			let uuid2 = Uuid4::generate();
988
989			layout.set_uuid4(&mut key1, 0, uuid1.clone());
990			layout.set_uuid4(&mut key2, 0, uuid2.clone());
991
992			// Check bitvec shows field is set
993			assert!(key1.is_defined(0));
994			assert!(key2.is_defined(0));
995
996			// Check values are stored correctly (16 bytes)
997			let offset = layout.fields[0].offset;
998			let uuid1_bytes: Vec<u8> = uuid1.as_bytes().to_vec();
999			let uuid2_bytes: Vec<u8> = uuid2.as_bytes().to_vec();
1000
1001			assert_eq!(&key1[offset..offset + 16], &uuid1_bytes[..]);
1002			assert_eq!(&key2[offset..offset + 16], &uuid2_bytes[..]);
1003		}
1004
1005		#[test]
1006		fn test_desc() {
1007			let layout = IndexShape::new(&[ValueType::Uuid4], &[SortDirection::Desc]).unwrap();
1008			let mut key = layout.allocate_key();
1009
1010			let uuid = Uuid4::generate();
1011			layout.set_uuid4(&mut key, 0, uuid.clone());
1012
1013			// Check value is inverted for DESC
1014			let offset = layout.fields[0].offset;
1015			let mut expected_bytes = uuid.as_bytes().to_vec();
1016			for b in expected_bytes.iter_mut() {
1017				*b = !*b;
1018			}
1019
1020			assert_eq!(&key[offset..offset + 16], &expected_bytes[..]);
1021		}
1022	}
1023
1024	mod uuid7 {
1025		use reifydb_runtime::context::{
1026			clock::{Clock, MockClock},
1027			rng::Rng,
1028		};
1029		use reifydb_value::value::{uuid::Uuid7, value_type::ValueType};
1030
1031		use crate::{sort::SortDirection, value::index::shape::IndexShape};
1032
1033		fn test_clock_and_rng() -> (MockClock, Clock, Rng) {
1034			let mock = MockClock::from_millis(1000);
1035			let clock = Clock::Mock(mock.clone());
1036			let rng = Rng::seeded(42);
1037			(mock, clock, rng)
1038		}
1039
1040		#[test]
1041		fn test_asc() {
1042			let (mock, clock, rng) = test_clock_and_rng();
1043			let layout = IndexShape::new(&[ValueType::Uuid7], &[SortDirection::Asc]).unwrap();
1044			let mut key1 = layout.allocate_key();
1045			let mut key2 = layout.allocate_key();
1046
1047			let uuid1 = Uuid7::generate(&clock, &rng);
1048			// Advance clock to ensure different timestamps
1049			mock.advance_millis(10);
1050			let uuid2 = Uuid7::generate(&clock, &rng);
1051
1052			layout.set_uuid7(&mut key1, 0, uuid1.clone());
1053			layout.set_uuid7(&mut key2, 0, uuid2.clone());
1054
1055			// Check bitvec shows field is set
1056			assert!(key1.is_defined(0));
1057			assert!(key2.is_defined(0));
1058
1059			// Check values are stored correctly (16 bytes)
1060			let offset = layout.fields[0].offset;
1061			let uuid1_bytes: Vec<u8> = uuid1.as_bytes().to_vec();
1062			let uuid2_bytes: Vec<u8> = uuid2.as_bytes().to_vec();
1063
1064			assert_eq!(&key1[offset..offset + 16], &uuid1_bytes[..]);
1065			assert_eq!(&key2[offset..offset + 16], &uuid2_bytes[..]);
1066
1067			// UUID7 has timestamp prefix, so later should be
1068			// greater
1069			assert!(key1.as_slice() < key2.as_slice());
1070		}
1071
1072		#[test]
1073		fn test_desc() {
1074			let (mock, clock, rng) = test_clock_and_rng();
1075			let layout = IndexShape::new(&[ValueType::Uuid7], &[SortDirection::Desc]).unwrap();
1076			let mut key1 = layout.allocate_key();
1077			let mut key2 = layout.allocate_key();
1078
1079			let uuid1 = Uuid7::generate(&clock, &rng);
1080			// Advance clock to ensure different timestamps
1081			mock.advance_millis(10);
1082			let uuid2 = Uuid7::generate(&clock, &rng);
1083
1084			layout.set_uuid7(&mut key1, 0, uuid1.clone());
1085			layout.set_uuid7(&mut key2, 0, uuid2.clone());
1086
1087			// Check values are inverted for DESC
1088			let offset = layout.fields[0].offset;
1089			let mut expected_bytes1 = uuid1.as_bytes().to_vec();
1090			let mut expected_bytes2 = uuid2.as_bytes().to_vec();
1091			for b in expected_bytes1.iter_mut() {
1092				*b = !*b;
1093			}
1094			for b in expected_bytes2.iter_mut() {
1095				*b = !*b;
1096			}
1097
1098			assert_eq!(&key1[offset..offset + 16], &expected_bytes1[..]);
1099			assert_eq!(&key2[offset..offset + 16], &expected_bytes2[..]);
1100
1101			// Verify ordering (reversed due to DESC)
1102			assert!(key1.as_slice() > key2.as_slice());
1103		}
1104	}
1105
1106	mod identity_id {
1107		use reifydb_runtime::context::{
1108			clock::{Clock, MockClock},
1109			rng::Rng,
1110		};
1111		use reifydb_value::value::{identity::IdentityId, uuid::Uuid7, value_type::ValueType};
1112
1113		use crate::{sort::SortDirection, value::index::shape::IndexShape};
1114
1115		fn test_clock_and_rng() -> (MockClock, Clock, Rng) {
1116			let mock = MockClock::from_millis(1000);
1117			let clock = Clock::Mock(mock.clone());
1118			let rng = Rng::seeded(42);
1119			(mock, clock, rng)
1120		}
1121
1122		#[test]
1123		fn test_asc() {
1124			let (mock, clock, rng) = test_clock_and_rng();
1125			let layout = IndexShape::new(&[ValueType::IdentityId], &[SortDirection::Asc]).unwrap();
1126			let mut key1 = layout.allocate_key();
1127			let mut key2 = layout.allocate_key();
1128
1129			let id1 = IdentityId::generate(&clock, &rng);
1130			// Advance clock to ensure different timestamps
1131			// (IdentityId wraps Uuid7)
1132			mock.advance_millis(10);
1133			let id2 = IdentityId::generate(&clock, &rng);
1134
1135			layout.set_identity_id(&mut key1, 0, id1.clone());
1136			layout.set_identity_id(&mut key2, 0, id2.clone());
1137
1138			// Check bitvec shows field is set
1139			assert!(key1.is_defined(0));
1140			assert!(key2.is_defined(0));
1141
1142			// Check values are stored correctly (16 bytes)
1143			let offset = layout.fields[0].offset;
1144			let uuid7_1: Uuid7 = id1.into();
1145			let uuid7_2: Uuid7 = id2.into();
1146			let id1_bytes: Vec<u8> = uuid7_1.as_bytes().to_vec();
1147			let id2_bytes: Vec<u8> = uuid7_2.as_bytes().to_vec();
1148
1149			assert_eq!(&key1[offset..offset + 16], &id1_bytes[..]);
1150			assert_eq!(&key2[offset..offset + 16], &id2_bytes[..]);
1151
1152			// IdentityId wraps Uuid7 which has timestamp prefix, so
1153			// later should be greater
1154			assert!(key1.as_slice() < key2.as_slice());
1155		}
1156
1157		#[test]
1158		fn test_desc() {
1159			let (mock, clock, rng) = test_clock_and_rng();
1160			let layout = IndexShape::new(&[ValueType::IdentityId], &[SortDirection::Desc]).unwrap();
1161			let mut key1 = layout.allocate_key();
1162			let mut key2 = layout.allocate_key();
1163
1164			let id1 = IdentityId::generate(&clock, &rng);
1165			// Advance clock to ensure different timestamps
1166			mock.advance_millis(10);
1167			let id2 = IdentityId::generate(&clock, &rng);
1168
1169			layout.set_identity_id(&mut key1, 0, id1.clone());
1170			layout.set_identity_id(&mut key2, 0, id2.clone());
1171
1172			// Check values are inverted for DESC
1173			let offset = layout.fields[0].offset;
1174			let uuid7_1: Uuid7 = id1.into();
1175			let uuid7_2: Uuid7 = id2.into();
1176			let mut expected_bytes1 = uuid7_1.as_bytes().to_vec();
1177			let mut expected_bytes2 = uuid7_2.as_bytes().to_vec();
1178			for b in expected_bytes1.iter_mut() {
1179				*b = !*b;
1180			}
1181			for b in expected_bytes2.iter_mut() {
1182				*b = !*b;
1183			}
1184
1185			assert_eq!(&key1[offset..offset + 16], &expected_bytes1[..]);
1186			assert_eq!(&key2[offset..offset + 16], &expected_bytes2[..]);
1187
1188			// Verify ordering (reversed due to DESC)
1189			assert!(key1.as_slice() > key2.as_slice());
1190		}
1191	}
1192
1193	mod undefined {
1194		use reifydb_value::value::value_type::ValueType;
1195
1196		use crate::{sort::SortDirection, value::index::shape::IndexShape};
1197
1198		#[test]
1199		fn test_undefined() {
1200			let layout = IndexShape::new(&[ValueType::Int4], &[SortDirection::Asc]).unwrap();
1201			let mut key = layout.allocate_key();
1202
1203			// Set a value first
1204			layout.set_i32(&mut key, 0, 42);
1205			assert!(key.is_defined(0));
1206
1207			// Now set it to undefined
1208			layout.set_none(&mut key, 0);
1209			assert!(!key.is_defined(0));
1210
1211			// Check that the data is zeroed
1212			let offset = layout.fields[0].offset;
1213			assert_eq!(&key[offset..offset + 4], &[0, 0, 0, 0]);
1214		}
1215	}
1216}