Skip to main content

reifydb_core/value/index/
set.rs

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