Skip to main content

reifydb_value/value/container/
uuid_array.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4use std::{mem::ManuallyDrop, ops::Deref, slice};
5
6use arrow_array::{Array, FixedSizeBinaryArray};
7use arrow_buffer::Buffer;
8use uuid::Uuid;
9
10use crate::value::{
11	Value,
12	identity::IdentityId,
13	is::IsUuid,
14	uuid::{Uuid4, Uuid7},
15	value_type::ValueType,
16};
17
18pub const UUID_WIDTH: usize = 16;
19
20fn rows(array: &FixedSizeBinaryArray) -> &[u8] {
21	assert_eq!(
22		array.value_length() as usize,
23		UUID_WIDTH,
24		"uuid column must hold {UUID_WIDTH} byte values, found {}",
25		array.value_length()
26	);
27	&array.value_data()[..array.len() * UUID_WIDTH]
28}
29
30pub fn uuid4s(array: &FixedSizeBinaryArray) -> &[Uuid4] {
31	let bytes = rows(array);
32	// SAFETY: Uuid4 is repr(transparent) over [u8; 16] with align 1 and no niche, and bytes holds exactly len rows.
33	unsafe { slice::from_raw_parts(bytes.as_ptr().cast::<Uuid4>(), array.len()) }
34}
35
36pub fn uuid7s(array: &FixedSizeBinaryArray) -> &[Uuid7] {
37	let bytes = rows(array);
38	// SAFETY: Uuid7 is repr(transparent) over [u8; 16] with align 1 and no niche, and bytes holds exactly len rows.
39	unsafe { slice::from_raw_parts(bytes.as_ptr().cast::<Uuid7>(), array.len()) }
40}
41
42pub fn identity_ids(array: &FixedSizeBinaryArray) -> &[IdentityId] {
43	let bytes = rows(array);
44	// SAFETY: IdentityId is repr(transparent) over the 16 byte, align 1 Uuid7, and bytes holds exactly len rows.
45	unsafe { slice::from_raw_parts(bytes.as_ptr().cast::<IdentityId>(), array.len()) }
46}
47
48fn collect_rows<T: IsUuid + Copy>(values: impl IntoIterator<Item = T>) -> FixedSizeBinaryArray {
49	const { assert!(size_of::<T>() == UUID_WIDTH && align_of::<T>() == 1) };
50	let mut rows = ManuallyDrop::new(values.into_iter().collect::<Vec<T>>());
51	let (ptr, len, capacity) = (rows.as_mut_ptr(), rows.len(), rows.capacity());
52	// SAFETY: T is repr(transparent) over Uuid, 16 bytes, align 1: cap * 16 u8 has its layout, any byte is valid.
53	let bytes = unsafe { Vec::from_raw_parts(ptr.cast::<u8>(), len * UUID_WIDTH, capacity * UUID_WIDTH) };
54	FixedSizeBinaryArray::new(UUID_WIDTH as i32, Buffer::from_vec(bytes), None)
55}
56
57pub fn uuid4_array(values: impl IntoIterator<Item = Uuid4>) -> FixedSizeBinaryArray {
58	collect_rows(values)
59}
60
61pub fn uuid7_array(values: impl IntoIterator<Item = Uuid7>) -> FixedSizeBinaryArray {
62	collect_rows(values)
63}
64
65pub fn identity_id_array(values: impl IntoIterator<Item = IdentityId>) -> FixedSizeBinaryArray {
66	collect_rows(values)
67}
68
69pub fn get_value<T>(values: &[T], index: usize) -> Value
70where
71	T: IsUuid + Copy + Deref<Target = Uuid>,
72{
73	if index < values.len() {
74		values[index].to_value()
75	} else {
76		Value::none()
77	}
78}
79
80pub fn identity_id_get_value(values: &[IdentityId], index: usize) -> Value {
81	if index < values.len() {
82		Value::IdentityId(values[index])
83	} else {
84		Value::none_of(ValueType::IdentityId)
85	}
86}
87
88pub fn as_string<T: IsUuid>(values: &[T], index: usize) -> String {
89	if index < values.len() {
90		values[index].to_string()
91	} else {
92		"none".to_string()
93	}
94}
95
96#[cfg(test)]
97mod tests {
98	use super::*;
99
100	#[test]
101	fn uuid7_array_takes_the_vec_allocation_without_copying() {
102		// Without the reinterpret, building a uuid column copies every row, 16 bytes at a time.
103		let mut values = Vec::with_capacity(8);
104		for i in 1..=3u128 {
105			values.push(Uuid7(Uuid::from_u128(0x0190_0000_0000_7000_8000_0000_0000_0000 | i)));
106		}
107		assert!(values.capacity() > values.len());
108		let expected = values.clone();
109		let ptr = values.as_ptr().cast::<u8>();
110
111		let array = uuid7_array(values);
112
113		assert_eq!(array.value_data().as_ptr(), ptr);
114		assert_eq!(array.len(), expected.len());
115		assert_eq!(uuid7s(&array), expected.as_slice());
116		for (i, value) in expected.iter().enumerate() {
117			assert_eq!(array.value(i), value.as_bytes());
118		}
119	}
120}