1use crate::{QByteArray, QString};
6use cxx::{type_id, ExternType};
7use std::{fmt, mem};
8#[cfg(feature = "uuid")]
9use uuid::Uuid;
10
11#[cxx::bridge]
12mod ffi {
13 #[namespace = "rust::cxxqtlib1"]
15 #[repr(i32)]
16 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
17 enum QUuidVariant {
18 VarUnknown = -1,
20 NCS = 0,
22 DCE = 2,
24 Microsoft = 6,
26 Reserved = 7,
28 }
29
30 #[namespace = "rust::cxxqtlib1"]
32 #[repr(i32)]
33 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
34 enum QUuidVersion {
35 VerUnknown = -1,
37 Time = 1,
40 EmbeddedPOSIX = 2,
42 Md5 = 3,
44 Random = 4,
46 Sha1 = 5,
47 }
48
49 extern "C++" {
50 include!("cxx-qt-lib/qbytearray.h");
51 type QByteArray = crate::QByteArray;
52 include!("cxx-qt-lib/qstring.h");
53 type QString = crate::QString;
54 }
55
56 #[namespace = "rust::cxxqtlib1"]
57 extern "C++" {
58 include!("cxx-qt-lib/quuid.h");
59 type QUuidVariant;
60 type QUuidVersion;
61 }
62
63 unsafe extern "C++" {
64 type QUuid = super::QUuid;
65
66 #[Self = "QUuid"]
70 #[rust_name = "create_uuid"]
71 fn createUuid() -> QUuid;
72
73 #[rust_name = "to_rfc_4122"]
76 fn toRfc4122(self: &QUuid) -> QByteArray;
77 }
78
79 #[namespace = "rust::cxxqtlib1"]
80 unsafe extern "C++" {
81 #[doc(hidden)]
82 #[rust_name = "quuid_create_uuid_v3"]
83 fn quuidCreateUuidV3(ns: &QUuid, data: &[u8]) -> QUuid;
84 #[doc(hidden)]
85 #[rust_name = "quuid_create_uuid_v5"]
86 fn quuidCreateUuidV5(ns: &QUuid, data: &[u8]) -> QUuid;
87 #[doc(hidden)]
88 #[rust_name = "quuid_to_string"]
89 fn quuidToString(uuid: &QUuid) -> QString;
90 #[doc(hidden)]
91 #[rust_name = "quuid_from_string"]
92 fn quuidFromString(string: &QString) -> QUuid;
93 #[doc(hidden)]
94 #[rust_name = "quuid_from_str"]
95 fn quuidFromStr(string: &str) -> QUuid;
96 #[doc(hidden)]
97 #[rust_name = "quuid_from_rfc_4122"]
98 fn quuidFromRfc4122(bytes: &QByteArray) -> QUuid;
99
100 #[doc(hidden)]
104 #[rust_name = "quuid_variant"]
105 fn quuidVariant(quuid: &QUuid) -> QUuidVariant;
106 #[doc(hidden)]
107 #[rust_name = "quuid_version"]
108 fn quuidVersion(quuid: &QUuid) -> QUuidVersion;
109
110 }
111}
112
113pub use ffi::{QUuidVariant, QUuidVersion};
114
115#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
119#[repr(C)]
120pub struct QUuid {
121 data1: u32,
122 data2: u16,
123 data3: u16,
124 data4: [u8; 8],
125}
126
127impl Default for QUuid {
128 fn default() -> Self {
131 Self::null()
132 }
133}
134
135impl fmt::Display for QUuid {
136 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
137 ffi::quuid_to_string(self).fmt(f)
138 }
139}
140
141impl fmt::Debug for QUuid {
142 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
143 ffi::quuid_to_string(self).fmt(f)
144 }
145}
146
147impl QUuid {
148 pub const fn null() -> Self {
151 Self {
152 data1: 0,
153 data2: 0,
154 data3: 0,
155 data4: [0; 8],
156 }
157 }
158
159 pub const fn is_null(&self) -> bool {
162 (unsafe { std::mem::transmute::<QUuid, u128>(*self) }) == 0
163 }
164
165 pub fn create_uuid_v3(namespace: &Self, data: &[u8]) -> Self {
169 ffi::quuid_create_uuid_v3(namespace, data)
170 }
171
172 pub fn create_uuid_v5(namespace: &Self, data: &[u8]) -> Self {
176 ffi::quuid_create_uuid_v5(namespace, data)
177 }
178
179 pub fn from_rfc_4122(bytes: &QByteArray) -> Self {
187 ffi::quuid_from_rfc_4122(bytes)
188 }
189
190 pub const fn from_fields(data1: u32, data2: u16, data3: u16, data4: [u8; 8]) -> Self {
192 Self {
193 data1,
194 data2,
195 data3,
196 data4,
197 }
198 }
199
200 pub const fn as_fields(&self) -> (u32, u16, u16, &[u8; 8]) {
201 (self.data1, self.data2, self.data3, &self.data4)
202 }
203
204 pub const fn from_bytes(bytes: [u8; 16]) -> Self {
206 unsafe { mem::transmute::<[u8; 16], Self>(bytes) }.to_be()
209 }
210
211 pub const fn to_bytes(self) -> [u8; 16] {
213 unsafe { mem::transmute::<Self, [u8; 16]>(self.to_be()) }
216 }
217
218 pub const fn from_u128(data: u128) -> Self {
220 Self::from_bytes(data.to_be_bytes())
221 }
222
223 pub const fn to_u128(&self) -> u128 {
225 u128::from_be_bytes(self.to_bytes())
226 }
227
228 #[must_use = "this returns the result of the operation, without modifying the original"]
236 const fn to_be(self) -> Self {
237 #[cfg(target_endian = "big")]
238 {
239 self
240 }
241 #[cfg(target_endian = "little")]
242 {
243 Self {
244 data1: self.data1.swap_bytes(),
245 data2: self.data2.swap_bytes(),
246 data3: self.data3.swap_bytes(),
247 data4: self.data4,
248 }
249 }
250 }
251
252 pub fn variant(&self) -> QUuidVariant {
256 ffi::quuid_variant(self)
257 }
258
259 pub fn version(&self) -> QUuidVersion {
262 ffi::quuid_version(self)
263 }
264}
265
266unsafe impl ExternType for QUuid {
267 type Id = type_id!("QUuid");
268 type Kind = cxx::kind::Trivial;
269}
270
271impl From<QUuid> for QString {
272 fn from(value: QUuid) -> Self {
273 ffi::quuid_to_string(&value)
274 }
275}
276
277impl From<u128> for QUuid {
278 fn from(value: u128) -> Self {
279 Self::from_u128(value)
280 }
281}
282
283impl From<QUuid> for u128 {
284 fn from(value: QUuid) -> Self {
285 value.to_u128()
286 }
287}
288
289impl From<&QString> for QUuid {
290 fn from(value: &QString) -> Self {
296 ffi::quuid_from_string(value)
297 }
298}
299
300impl From<&str> for QUuid {
301 fn from(value: &str) -> Self {
307 ffi::quuid_from_str(value)
308 }
309}
310
311impl From<&String> for QUuid {
312 fn from(value: &String) -> Self {
318 ffi::quuid_from_str(value)
319 }
320}
321
322impl From<&QByteArray> for QUuid {
323 fn from(value: &QByteArray) -> Self {
325 ffi::quuid_from_rfc_4122(value)
326 }
327}
328
329impl From<QUuid> for QByteArray {
330 fn from(value: QUuid) -> Self {
332 value.to_rfc_4122()
333 }
334}
335
336#[cfg(feature = "uuid")]
337impl From<Uuid> for QUuid {
338 fn from(value: Uuid) -> Self {
339 let (data1, data2, data3, &data4) = value.as_fields();
340 Self {
341 data1,
342 data2,
343 data3,
344 data4,
345 }
346 }
347}
348
349#[cfg(feature = "uuid")]
350impl From<QUuid> for Uuid {
351 fn from(value: QUuid) -> Self {
352 Self::from_fields(value.data1, value.data2, value.data3, &value.data4)
353 }
354}
355
356#[cfg(test)]
357mod test {
358 use super::*;
359
360 const NAMESPACE_DNS: &QUuid = &QUuid::from_u128(0x6ba7b8109dad11d180b400c04fd430c);
361
362 #[test]
363 fn quuid_is_null() {
364 assert!(QUuid::null().is_null())
365 }
366
367 #[test]
368 fn quuid_is_not_null() {
369 assert!(!QUuid::create_uuid().is_null())
370 }
371
372 #[test]
373 fn quuid_variant() {
374 assert_eq!(
375 [QUuid::null().variant(), QUuid::create_uuid().variant()],
376 [QUuidVariant::VarUnknown, QUuidVariant::DCE]
377 );
378 }
379
380 #[test]
381 fn quuid_version() {
382 assert_eq!(
383 [
384 QUuid::null().version(),
385 QUuid::create_uuid_v3(NAMESPACE_DNS, &[]).version(),
386 QUuid::create_uuid().version(),
387 QUuid::create_uuid_v5(NAMESPACE_DNS, &[]).version(),
388 ],
389 [
390 QUuidVersion::VerUnknown,
391 QUuidVersion::Md5,
392 QUuidVersion::Random,
393 QUuidVersion::Sha1
394 ]
395 )
396 }
397
398 #[test]
399 fn quuid_to_rfc_4122() {
400 let bytes = <[u8; 16]>::try_from("random test data".as_bytes()).unwrap();
401 assert_eq!(Vec::from(&QUuid::from_bytes(bytes).to_rfc_4122()), bytes)
402 }
403
404 #[test]
405 fn quuid_null() {
406 assert_eq!(QUuid::null(), QUuid::from_u128(0));
407 }
408
409 #[test]
410 fn quuid_new_v3() {
411 assert_eq!(
412 QUuid::create_uuid_v3(NAMESPACE_DNS, "testdata".as_bytes()),
413 QUuid::from_u128(0x5157facac7e1345c927671c2c6d41e7a)
414 );
415 }
416
417 #[test]
418 fn quuid_new_v4() {
419 assert_ne!(QUuid::create_uuid(), QUuid::create_uuid());
420 }
421
422 #[test]
423 fn quuid_new_v5() {
424 assert_eq!(
425 QUuid::create_uuid_v5(NAMESPACE_DNS, "testdata".as_bytes()),
426 QUuid::from_u128(0x7e95e361a22c51c18c297ac24cb61e83)
427 );
428 }
429
430 #[test]
431 fn quuid_to_string() {
432 assert_eq!(
433 QUuid::from_u128(0x7e95e361a22c51c18c297ac24cb61e83).to_string(),
434 "{7e95e361-a22c-51c1-8c29-7ac24cb61e83}"
435 )
436 }
437
438 #[test]
439 fn quuid_qstring_round_trip() {
440 let uuid = QUuid::create_uuid();
441 let roundtrip = QUuid::from(&QString::from(&uuid.to_string()));
442 assert_eq!(uuid, roundtrip)
443 }
444
445 #[test]
446 fn quuid_str_round_trip() {
447 let uuid = QUuid::create_uuid();
448 let roundtrip = QUuid::from(&uuid.to_string());
449 assert_eq!(uuid, roundtrip)
450 }
451
452 #[test]
453 fn quuid_fields_round_trip() {
454 let uuid = QUuid::create_uuid();
455 let (d1, d2, d3, &d4) = uuid.as_fields();
456 let roundtrip = QUuid::from_fields(d1, d2, d3, d4);
457 assert_eq!(uuid, roundtrip)
458 }
459
460 #[test]
461 fn quuid_bytes_round_trip() {
462 let uuid = QUuid::create_uuid();
463 let roundtrip = QUuid::from_bytes(uuid.to_bytes());
464 assert_eq!(uuid, roundtrip)
465 }
466
467 #[test]
468 fn quuid_qbytearray_round_trip() {
469 let uuid = QUuid::create_uuid();
470 let roundtrip = QUuid::from_rfc_4122(&uuid.to_rfc_4122());
471 assert_eq!(uuid, roundtrip)
472 }
473
474 #[test]
475 fn quuid_u128_round_trip() {
476 let uuid = QUuid::create_uuid();
477 let roundtrip = QUuid::from_u128(uuid.to_u128());
478 assert_eq!(uuid, roundtrip)
479 }
480}