Skip to main content

reifydb_core/value/index/
set.rs

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