Skip to main content

reifydb_core/encoded/
uuid4.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later
2// Copyright (c) 2025 ReifyDB
3
4use std::ptr;
5
6use reifydb_type::value::{r#type::Type, uuid::Uuid4};
7use uuid::Uuid;
8
9use crate::encoded::{encoded::EncodedValues, schema::Schema};
10
11impl Schema {
12	pub fn set_uuid4(&self, row: &mut EncodedValues, index: usize, value: Uuid4) {
13		let field = &self.fields()[index];
14		debug_assert!(row.len() >= self.total_static_size());
15		debug_assert_eq!(*field.constraint.get_type().inner_type(), Type::Uuid4);
16		row.set_valid(index, true);
17		unsafe {
18			// UUIDs are 16 bytes
19			ptr::write_unaligned(
20				row.make_mut().as_mut_ptr().add(field.offset as usize) as *mut [u8; 16],
21				*value.as_bytes(),
22			);
23		}
24	}
25
26	pub fn get_uuid4(&self, row: &EncodedValues, index: usize) -> Uuid4 {
27		let field = &self.fields()[index];
28		debug_assert!(row.len() >= self.total_static_size());
29		debug_assert_eq!(*field.constraint.get_type().inner_type(), Type::Uuid4);
30		unsafe {
31			// UUIDs are 16 bytes
32			let bytes: [u8; 16] =
33				ptr::read_unaligned(row.as_ptr().add(field.offset as usize) as *const [u8; 16]);
34			Uuid4::from(Uuid::from_bytes(bytes))
35		}
36	}
37
38	pub fn try_get_uuid4(&self, row: &EncodedValues, index: usize) -> Option<Uuid4> {
39		if row.is_defined(index) && self.fields()[index].constraint.get_type() == Type::Uuid4 {
40			Some(self.get_uuid4(row, index))
41		} else {
42			None
43		}
44	}
45}
46
47#[cfg(test)]
48pub mod tests {
49	use reifydb_type::value::{r#type::Type, uuid::Uuid4};
50
51	use crate::encoded::schema::Schema;
52
53	#[test]
54	fn test_set_get_uuid4() {
55		let schema = Schema::testing(&[Type::Uuid4]);
56		let mut row = schema.allocate();
57
58		let uuid = Uuid4::generate();
59		schema.set_uuid4(&mut row, 0, uuid.clone());
60		assert_eq!(schema.get_uuid4(&row, 0), uuid);
61	}
62
63	#[test]
64	fn test_try_get_uuid4() {
65		let schema = Schema::testing(&[Type::Uuid4]);
66		let mut row = schema.allocate();
67
68		assert_eq!(schema.try_get_uuid4(&row, 0), None);
69
70		let uuid = Uuid4::generate();
71		schema.set_uuid4(&mut row, 0, uuid.clone());
72		assert_eq!(schema.try_get_uuid4(&row, 0), Some(uuid));
73	}
74
75	#[test]
76	fn test_multiple_generations() {
77		let schema = Schema::testing(&[Type::Uuid4]);
78
79		// Generate multiple UUIDs and ensure they're different
80		let mut uuids = Vec::new();
81		for _ in 0..10 {
82			let mut row = schema.allocate();
83			let uuid = Uuid4::generate();
84			schema.set_uuid4(&mut row, 0, uuid.clone());
85			let retrieved = schema.get_uuid4(&row, 0);
86			assert_eq!(retrieved, uuid);
87			uuids.push(uuid);
88		}
89
90		// Ensure all generated UUIDs are unique
91		for i in 0..uuids.len() {
92			for j in (i + 1)..uuids.len() {
93				assert_ne!(uuids[i], uuids[j], "UUIDs should be unique");
94			}
95		}
96	}
97
98	#[test]
99	fn test_version_check() {
100		let schema = Schema::testing(&[Type::Uuid4]);
101		let mut row = schema.allocate();
102
103		let uuid = Uuid4::generate();
104		schema.set_uuid4(&mut row, 0, uuid.clone());
105		let retrieved = schema.get_uuid4(&row, 0);
106
107		// Verify it's a version 4 UUID
108		assert_eq!(retrieved.get_version_num(), 4);
109	}
110
111	#[test]
112	fn test_mixed_with_other_types() {
113		let schema = Schema::testing(&[Type::Uuid4, Type::Boolean, Type::Uuid4, Type::Int4]);
114		let mut row = schema.allocate();
115
116		let uuid1 = Uuid4::generate();
117		let uuid2 = Uuid4::generate();
118
119		schema.set_uuid4(&mut row, 0, uuid1.clone());
120		schema.set_bool(&mut row, 1, true);
121		schema.set_uuid4(&mut row, 2, uuid2.clone());
122		schema.set_i32(&mut row, 3, 42);
123
124		assert_eq!(schema.get_uuid4(&row, 0), uuid1);
125		assert_eq!(schema.get_bool(&row, 1), true);
126		assert_eq!(schema.get_uuid4(&row, 2), uuid2);
127		assert_eq!(schema.get_i32(&row, 3), 42);
128	}
129
130	#[test]
131	fn test_undefined_handling() {
132		let schema = Schema::testing(&[Type::Uuid4, Type::Uuid4]);
133		let mut row = schema.allocate();
134
135		let uuid = Uuid4::generate();
136		schema.set_uuid4(&mut row, 0, uuid.clone());
137
138		assert_eq!(schema.try_get_uuid4(&row, 0), Some(uuid));
139		assert_eq!(schema.try_get_uuid4(&row, 1), None);
140
141		schema.set_undefined(&mut row, 0);
142		assert_eq!(schema.try_get_uuid4(&row, 0), None);
143	}
144
145	#[test]
146	fn test_persistence() {
147		let schema = Schema::testing(&[Type::Uuid4]);
148		let mut row = schema.allocate();
149
150		let uuid = Uuid4::generate();
151		let uuid_string = uuid.to_string();
152
153		schema.set_uuid4(&mut row, 0, uuid.clone());
154		let retrieved = schema.get_uuid4(&row, 0);
155
156		assert_eq!(retrieved, uuid);
157		assert_eq!(retrieved.to_string(), uuid_string);
158		assert_eq!(retrieved.as_bytes(), uuid.as_bytes());
159	}
160
161	#[test]
162	fn test_clone_consistency() {
163		let schema = Schema::testing(&[Type::Uuid4]);
164		let mut row = schema.allocate();
165
166		let original_uuid = Uuid4::generate();
167		schema.set_uuid4(&mut row, 0, original_uuid.clone());
168
169		let retrieved_uuid = schema.get_uuid4(&row, 0);
170		assert_eq!(retrieved_uuid, original_uuid);
171
172		// Verify that the byte representation is identical
173		assert_eq!(retrieved_uuid.as_bytes(), original_uuid.as_bytes());
174	}
175
176	#[test]
177	fn test_multiple_fields() {
178		let schema = Schema::testing(&[Type::Uuid4, Type::Uuid4, Type::Uuid4]);
179		let mut row = schema.allocate();
180
181		let uuid1 = Uuid4::generate();
182		let uuid2 = Uuid4::generate();
183		let uuid3 = Uuid4::generate();
184
185		schema.set_uuid4(&mut row, 0, uuid1.clone());
186		schema.set_uuid4(&mut row, 1, uuid2.clone());
187		schema.set_uuid4(&mut row, 2, uuid3.clone());
188
189		assert_eq!(schema.get_uuid4(&row, 0), uuid1);
190		assert_eq!(schema.get_uuid4(&row, 1), uuid2);
191		assert_eq!(schema.get_uuid4(&row, 2), uuid3);
192
193		// Ensure all UUIDs are different
194		assert_ne!(uuid1, uuid2);
195		assert_ne!(uuid1, uuid3);
196		assert_ne!(uuid2, uuid3);
197	}
198
199	#[test]
200	fn test_format_consistency() {
201		let schema = Schema::testing(&[Type::Uuid4]);
202		let mut row = schema.allocate();
203
204		let uuid = Uuid4::generate();
205		let original_string = uuid.to_string();
206
207		schema.set_uuid4(&mut row, 0, uuid.clone());
208		let retrieved = schema.get_uuid4(&row, 0);
209		let retrieved_string = retrieved.to_string();
210
211		assert_eq!(original_string, retrieved_string);
212
213		// Verify UUID string format (8-4-4-4-12)
214		assert_eq!(original_string.len(), 36);
215		assert_eq!(original_string.matches('-').count(), 4);
216	}
217
218	#[test]
219	fn test_byte_level_storage() {
220		let schema = Schema::testing(&[Type::Uuid4]);
221		let mut row = schema.allocate();
222
223		let uuid = Uuid4::generate();
224		let original_bytes = *uuid.as_bytes();
225
226		schema.set_uuid4(&mut row, 0, uuid.clone());
227		let retrieved = schema.get_uuid4(&row, 0);
228		let retrieved_bytes = *retrieved.as_bytes();
229
230		assert_eq!(original_bytes, retrieved_bytes);
231
232		// Verify that it's exactly 16 bytes
233		assert_eq!(original_bytes.len(), 16);
234		assert_eq!(retrieved_bytes.len(), 16);
235	}
236
237	#[test]
238	fn test_try_get_uuid4_wrong_type() {
239		let schema = Schema::testing(&[Type::Boolean]);
240		let mut row = schema.allocate();
241
242		schema.set_bool(&mut row, 0, true);
243
244		assert_eq!(schema.try_get_uuid4(&row, 0), None);
245	}
246}