1#[cfg(feature = "alloc")]
12use alloc::alloc::{Layout, alloc, dealloc};
13use core::fmt::{self, Debug, Formatter};
14use core::hash::{Hash, Hasher};
15
16use crate::value::{TypeTag, Value};
17
18#[repr(u8)]
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
23pub enum OtherKind {
24 QName = 0,
26 Uuid = 1,
28}
29
30#[repr(C, align(8))]
38struct QNameHeader {
39 kind: OtherKind,
41 _pad: [u8; 7],
43 namespace: Value,
45 local_name: Value,
47}
48
49#[repr(transparent)]
57pub struct VQName(pub(crate) Value);
58
59impl VQName {
60 fn layout() -> Layout {
61 Layout::new::<QNameHeader>()
62 }
63
64 #[cfg(feature = "alloc")]
65 fn alloc() -> *mut QNameHeader {
66 unsafe { alloc(Self::layout()).cast::<QNameHeader>() }
67 }
68
69 #[cfg(feature = "alloc")]
70 fn dealloc(ptr: *mut QNameHeader) {
71 unsafe {
72 dealloc(ptr.cast::<u8>(), Self::layout());
73 }
74 }
75
76 fn header(&self) -> &QNameHeader {
77 unsafe { &*(self.0.heap_ptr() as *const QNameHeader) }
78 }
79
80 #[cfg(feature = "alloc")]
82 #[must_use]
83 pub fn new(namespace: impl Into<Value>, local_name: impl Into<Value>) -> Self {
84 unsafe {
85 let ptr = Self::alloc();
86 core::ptr::write(&raw mut (*ptr).kind, OtherKind::QName);
88 core::ptr::write(&raw mut (*ptr)._pad, [0; 7]);
89 core::ptr::write(&raw mut (*ptr).namespace, namespace.into());
90 core::ptr::write(&raw mut (*ptr).local_name, local_name.into());
91 VQName(Value::new_ptr(ptr.cast(), TypeTag::Other))
92 }
93 }
94
95 #[cfg(feature = "alloc")]
97 #[must_use]
98 pub fn new_local(local_name: impl Into<Value>) -> Self {
99 Self::new(Value::NULL, local_name)
100 }
101
102 #[must_use]
104 pub fn namespace(&self) -> Option<&Value> {
105 let ns = &self.header().namespace;
106 if ns.is_null() { None } else { Some(ns) }
107 }
108
109 #[must_use]
111 pub fn local_name(&self) -> &Value {
112 &self.header().local_name
113 }
114
115 #[must_use]
117 pub fn has_namespace(&self) -> bool {
118 !self.header().namespace.is_null()
119 }
120
121 pub(crate) fn clone_impl(&self) -> Value {
124 #[cfg(feature = "alloc")]
125 {
126 let h = self.header();
127 Self::new(h.namespace.clone(), h.local_name.clone()).0
128 }
129 #[cfg(not(feature = "alloc"))]
130 {
131 panic!("cannot clone VQName without alloc feature")
132 }
133 }
134
135 pub(crate) fn drop_impl(&mut self) {
136 #[cfg(feature = "alloc")]
137 unsafe {
138 let ptr = self.0.heap_ptr_mut() as *mut QNameHeader;
139 core::ptr::drop_in_place(&mut (*ptr).namespace);
141 core::ptr::drop_in_place(&mut (*ptr).local_name);
142 Self::dealloc(ptr);
143 }
144 }
145}
146
147impl Clone for VQName {
148 fn clone(&self) -> Self {
149 VQName(self.clone_impl())
150 }
151}
152
153impl PartialEq for VQName {
154 fn eq(&self, other: &Self) -> bool {
155 let (h1, h2) = (self.header(), other.header());
156 h1.namespace == h2.namespace && h1.local_name == h2.local_name
157 }
158}
159
160impl Eq for VQName {}
161
162impl Hash for VQName {
163 fn hash<H: Hasher>(&self, state: &mut H) {
164 let h = self.header();
165 h.namespace.hash(state);
166 h.local_name.hash(state);
167 }
168}
169
170impl Debug for VQName {
171 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
172 let h = self.header();
173 if h.namespace.is_null() {
174 write!(f, "{:?}", h.local_name)
175 } else {
176 write!(f, "{{{:?}}}{:?}", h.namespace, h.local_name)
177 }
178 }
179}
180
181#[cfg(feature = "alloc")]
182impl From<VQName> for Value {
183 fn from(qname: VQName) -> Self {
184 qname.0
185 }
186}
187
188#[repr(C, align(8))]
196struct UuidHeader {
197 kind: OtherKind,
199 _pad: [u8; 7],
201 bytes: [u8; 16],
203}
204
205#[repr(transparent)]
211pub struct VUuid(pub(crate) Value);
212
213impl VUuid {
214 fn layout() -> Layout {
215 Layout::new::<UuidHeader>()
216 }
217
218 #[cfg(feature = "alloc")]
219 fn alloc() -> *mut UuidHeader {
220 unsafe { alloc(Self::layout()).cast::<UuidHeader>() }
221 }
222
223 #[cfg(feature = "alloc")]
224 fn dealloc(ptr: *mut UuidHeader) {
225 unsafe {
226 dealloc(ptr.cast::<u8>(), Self::layout());
227 }
228 }
229
230 fn header(&self) -> &UuidHeader {
231 unsafe { &*(self.0.heap_ptr() as *const UuidHeader) }
232 }
233
234 #[cfg(feature = "alloc")]
236 #[must_use]
237 pub fn new(bytes: [u8; 16]) -> Self {
238 unsafe {
239 let ptr = Self::alloc();
240 core::ptr::write(&raw mut (*ptr).kind, OtherKind::Uuid);
242 core::ptr::write(&raw mut (*ptr)._pad, [0; 7]);
243 core::ptr::write(&raw mut (*ptr).bytes, bytes);
244 VUuid(Value::new_ptr(ptr.cast(), TypeTag::Other))
245 }
246 }
247
248 #[cfg(feature = "alloc")]
250 #[must_use]
251 pub fn from_u64_pair(high: u64, low: u64) -> Self {
252 let mut bytes = [0u8; 16];
253 bytes[..8].copy_from_slice(&high.to_be_bytes());
254 bytes[8..].copy_from_slice(&low.to_be_bytes());
255 Self::new(bytes)
256 }
257
258 #[cfg(feature = "alloc")]
260 #[must_use]
261 pub fn from_u128(value: u128) -> Self {
262 Self::new(value.to_be_bytes())
263 }
264
265 #[must_use]
267 pub fn as_bytes(&self) -> &[u8; 16] {
268 &self.header().bytes
269 }
270
271 #[must_use]
273 pub fn as_u128(&self) -> u128 {
274 u128::from_be_bytes(self.header().bytes)
275 }
276
277 #[must_use]
279 pub fn high(&self) -> u64 {
280 let bytes = &self.header().bytes;
281 u64::from_be_bytes([
282 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
283 ])
284 }
285
286 #[must_use]
288 pub fn low(&self) -> u64 {
289 let bytes = &self.header().bytes;
290 u64::from_be_bytes([
291 bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15],
292 ])
293 }
294
295 pub(crate) fn clone_impl(&self) -> Value {
298 #[cfg(feature = "alloc")]
299 {
300 Self::new(self.header().bytes).0
301 }
302 #[cfg(not(feature = "alloc"))]
303 {
304 panic!("cannot clone VUuid without alloc feature")
305 }
306 }
307
308 pub(crate) fn drop_impl(&mut self) {
309 #[cfg(feature = "alloc")]
310 unsafe {
311 Self::dealloc(self.0.heap_ptr_mut().cast());
312 }
313 }
314}
315
316impl Clone for VUuid {
317 fn clone(&self) -> Self {
318 VUuid(self.clone_impl())
319 }
320}
321
322impl PartialEq for VUuid {
323 fn eq(&self, other: &Self) -> bool {
324 self.header().bytes == other.header().bytes
325 }
326}
327
328impl Eq for VUuid {}
329
330impl Hash for VUuid {
331 fn hash<H: Hasher>(&self, state: &mut H) {
332 self.header().bytes.hash(state);
333 }
334}
335
336impl Debug for VUuid {
337 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
338 let bytes = &self.header().bytes;
339 write!(
341 f,
342 "{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
343 bytes[0],
344 bytes[1],
345 bytes[2],
346 bytes[3],
347 bytes[4],
348 bytes[5],
349 bytes[6],
350 bytes[7],
351 bytes[8],
352 bytes[9],
353 bytes[10],
354 bytes[11],
355 bytes[12],
356 bytes[13],
357 bytes[14],
358 bytes[15]
359 )
360 }
361}
362
363#[cfg(feature = "alloc")]
364impl From<VUuid> for Value {
365 fn from(uuid: VUuid) -> Self {
366 uuid.0
367 }
368}
369
370#[cfg(feature = "alloc")]
371impl From<[u8; 16]> for VUuid {
372 fn from(bytes: [u8; 16]) -> Self {
373 Self::new(bytes)
374 }
375}
376
377#[cfg(feature = "alloc")]
378impl From<u128> for VUuid {
379 fn from(value: u128) -> Self {
380 Self::from_u128(value)
381 }
382}
383
384pub(crate) unsafe fn get_other_kind(value: &Value) -> OtherKind {
393 let ptr = value.heap_ptr();
395 unsafe { *(ptr as *const OtherKind) }
396}
397
398#[cfg(test)]
399mod tests {
400 use super::*;
401 use crate::VString;
402
403 #[test]
404 fn test_qname_with_namespace() {
405 let qname = VQName::new(VString::new("http://example.com"), VString::new("element"));
406 assert!(qname.has_namespace());
407 assert_eq!(
408 qname.namespace().unwrap().as_string().unwrap().as_str(),
409 "http://example.com"
410 );
411 assert_eq!(qname.local_name().as_string().unwrap().as_str(), "element");
412 }
413
414 #[test]
415 fn test_qname_local_only() {
416 let qname = VQName::new_local(VString::new("element"));
417 assert!(!qname.has_namespace());
418 assert!(qname.namespace().is_none());
419 assert_eq!(qname.local_name().as_string().unwrap().as_str(), "element");
420 }
421
422 #[test]
423 fn test_qname_clone() {
424 let qname = VQName::new(VString::new("ns"), VString::new("local"));
425 let cloned = qname.clone();
426 assert_eq!(qname, cloned);
427 }
428
429 #[test]
430 fn test_qname_debug() {
431 let qname = VQName::new(VString::new("ns"), VString::new("local"));
432 let debug = format!("{qname:?}");
433 assert!(debug.contains("ns"));
434 assert!(debug.contains("local"));
435 }
436
437 #[test]
438 fn test_uuid_new() {
439 let bytes = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
440 let uuid = VUuid::new(bytes);
441 assert_eq!(uuid.as_bytes(), &bytes);
442 }
443
444 #[test]
445 fn test_uuid_from_u128() {
446 let value: u128 = 0x0102030405060708090a0b0c0d0e0f10;
447 let uuid = VUuid::from_u128(value);
448 assert_eq!(uuid.as_u128(), value);
449 }
450
451 #[test]
452 fn test_uuid_high_low() {
453 let uuid = VUuid::from_u64_pair(0x0102030405060708, 0x090a0b0c0d0e0f10);
454 assert_eq!(uuid.high(), 0x0102030405060708);
455 assert_eq!(uuid.low(), 0x090a0b0c0d0e0f10);
456 }
457
458 #[test]
459 fn test_uuid_clone() {
460 let uuid = VUuid::from_u128(0x12345678_9abc_def0_1234_56789abcdef0);
461 let cloned = uuid.clone();
462 assert_eq!(uuid, cloned);
463 }
464
465 #[test]
466 fn test_uuid_debug_format() {
467 let uuid = VUuid::from_u128(0x12345678_9abc_def0_1234_56789abcdef0);
468 let debug = format!("{uuid:?}");
469 assert_eq!(debug, "12345678-9abc-def0-1234-56789abcdef0");
470 }
471}