1#![allow(clippy::clone_on_copy)]
21
22use std::{
23 ffi::CStr,
24 fmt::{Debug, Display},
25 hash::Hash,
26 str::FromStr,
27};
28
29#[cfg(all(feature = "simulation", madsim))]
30use madsim::rand::RngCore as MadsimRngCore;
31use rand::Rng;
32use serde::{Deserialize, Deserializer, Serialize, Serializer};
33use uuid::Uuid;
34
35use crate::hex::ENCODE_PAIR;
36
37pub(crate) const UUID4_LEN: usize = 37;
39
40#[repr(C)]
43#[derive(Copy, Clone, Hash, PartialEq, Eq)]
44#[cfg_attr(
45 feature = "python",
46 pyo3::pyclass(module = "nautilus_trader.core", from_py_object)
47)]
48#[cfg_attr(
49 feature = "python",
50 pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.core")
51)]
52pub struct UUID4 {
53 pub(crate) value: [u8; 37], }
56
57impl UUID4 {
58 #[must_use]
62 pub fn new() -> Self {
63 let bytes = Self::new_bytes();
64 Self {
65 value: format_uuid4_bytes(bytes),
66 }
67 }
68
69 #[must_use]
71 pub fn new_bytes() -> [u8; 16] {
72 let mut bytes = [0u8; 16];
73 #[cfg(all(feature = "simulation", madsim))]
74 {
75 if madsim::runtime::Handle::try_current().is_ok() {
80 MadsimRngCore::fill_bytes(&mut madsim::rand::thread_rng(), &mut bytes);
81 } else {
82 rand::rng().fill_bytes(&mut bytes); }
84 }
85 #[cfg(not(all(feature = "simulation", madsim)))]
86 rand::rng().fill_bytes(&mut bytes);
87
88 bytes[6] = (bytes[6] & 0x0F) | 0x40; bytes[8] = (bytes[8] & 0x3F) | 0x80; bytes
92 }
93
94 #[must_use]
99 pub fn from_bytes(mut bytes: [u8; 16]) -> Self {
100 bytes[6] = (bytes[6] & 0x0F) | 0x40;
101 bytes[8] = (bytes[8] & 0x3F) | 0x80;
102 Self {
103 value: format_uuid4_bytes(bytes),
104 }
105 }
106
107 #[must_use]
113 pub fn to_cstr(&self) -> &CStr {
114 CStr::from_bytes_with_nul(&self.value)
116 .expect("UUID byte representation should be a valid C string")
117 }
118
119 #[must_use]
126 pub fn as_str(&self) -> &str {
127 self.to_cstr().to_str().expect("UUID should be valid UTF-8")
129 }
130
131 #[must_use]
141 pub fn as_bytes(&self) -> [u8; 16] {
142 let uuid_str = self.to_cstr().to_str().expect("Valid UTF-8");
143 let uuid = Uuid::parse_str(uuid_str).expect("Valid UUID4");
144 *uuid.as_bytes()
145 }
146
147 fn validate_v4(uuid: &Uuid) {
148 assert_eq!(
150 uuid.get_version(),
151 Some(uuid::Version::Random),
152 "UUID is not version 4"
153 );
154
155 assert_eq!(
157 uuid.get_variant(),
158 uuid::Variant::RFC4122,
159 "UUID is not RFC 4122 variant"
160 );
161 }
162
163 fn try_validate_v4(uuid: &Uuid) -> Result<(), String> {
164 if uuid.get_version() != Some(uuid::Version::Random) {
165 return Err("UUID is not version 4".to_string());
166 }
167
168 if uuid.get_variant() != uuid::Variant::RFC4122 {
169 return Err("UUID is not RFC 4122 variant".to_string());
170 }
171 Ok(())
172 }
173
174 fn from_validated_uuid(uuid: &Uuid) -> Self {
175 Self {
176 value: format_uuid4_bytes(*uuid.as_bytes()),
177 }
178 }
179}
180
181impl FromStr for UUID4 {
182 type Err = String;
183
184 fn from_str(value: &str) -> Result<Self, Self::Err> {
192 let uuid = Uuid::try_parse(value).map_err(|e| e.to_string())?;
193 Self::try_validate_v4(&uuid)?;
194 Ok(Self::from_validated_uuid(&uuid))
195 }
196}
197
198impl From<&str> for UUID4 {
199 fn from(value: &str) -> Self {
200 Self::from_str(value).expect("Invalid UUID4 string")
201 }
202}
203
204impl From<String> for UUID4 {
205 fn from(value: String) -> Self {
206 Self::from_str(&value).expect("Invalid UUID4 string")
207 }
208}
209
210impl From<uuid::Uuid> for UUID4 {
211 fn from(value: uuid::Uuid) -> Self {
217 Self::validate_v4(&value);
218 Self::from_validated_uuid(&value)
219 }
220}
221
222impl From<UUID4> for uuid::Uuid {
223 fn from(value: UUID4) -> Self {
225 Self::from_bytes(value.as_bytes())
226 }
227}
228
229impl Default for UUID4 {
230 fn default() -> Self {
234 Self::new()
235 }
236}
237
238impl Debug for UUID4 {
239 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
240 write!(f, "{}({})", stringify!(UUID4), self)
241 }
242}
243
244impl Display for UUID4 {
245 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
246 write!(f, "{}", self.to_cstr().to_string_lossy())
247 }
248}
249
250impl Serialize for UUID4 {
251 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
252 where
253 S: Serializer,
254 {
255 serializer.serialize_str(self.as_str())
256 }
257}
258
259impl<'de> Deserialize<'de> for UUID4 {
260 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
261 where
262 D: Deserializer<'de>,
263 {
264 let uuid4_str: std::borrow::Cow<'de, str> = Deserialize::deserialize(deserializer)?;
265 uuid4_str.as_ref().parse().map_err(serde::de::Error::custom)
266 }
267}
268
269fn format_uuid4_bytes(bytes: [u8; 16]) -> [u8; UUID4_LEN] {
270 let mut value = [0u8; UUID4_LEN];
271 let mut pos = 0;
272
273 for (idx, byte) in bytes.into_iter().enumerate() {
274 if matches!(idx, 4 | 6 | 8 | 10) {
275 value[pos] = b'-';
276 pos += 1;
277 }
278
279 value[pos..pos + 2].copy_from_slice(&ENCODE_PAIR[byte as usize]);
280 pos += 2;
281 }
282
283 value[36] = 0; debug_assert_eq!(pos, 36, "Invariant: UUID text must be 36 bytes");
286 debug_assert!(
287 value[14] == b'4',
288 "Invariant: UUID version digit must be '4' (was {})",
289 value[14] as char
290 );
291 debug_assert!(
292 matches!(value[19], b'8' | b'9' | b'a' | b'b'),
293 "Invariant: UUID variant byte must be RFC 4122 (was {})",
294 value[19] as char
295 );
296 debug_assert!(
297 value[36] == 0,
298 "Invariant: UUID null terminator must be at index 36"
299 );
300
301 value
302}
303
304#[cfg(test)]
305mod tests {
306 use std::{
307 collections::hash_map::DefaultHasher,
308 ffi::CStr,
309 hash::{Hash, Hasher},
310 };
311
312 use proptest::prelude::*;
313 use rstest::*;
314 use uuid;
315
316 use super::*;
317
318 #[rstest]
319 fn test_new() {
320 let uuid = UUID4::new();
321 let uuid_string = uuid.to_string();
322 let uuid_parsed = Uuid::parse_str(&uuid_string).unwrap();
323 assert_eq!(uuid_parsed.get_version().unwrap(), uuid::Version::Random);
324 assert_eq!(uuid_parsed.to_string().len(), 36);
325
326 assert_eq!(&uuid_string[14..15], "4");
328 let variant_char = &uuid_string[19..20];
330 assert!(matches!(variant_char, "8" | "9" | "a" | "b" | "A" | "B"));
331 }
332
333 #[rstest]
334 fn test_new_bytes() {
335 let bytes = UUID4::new_bytes();
336 let uuid = UUID4::from_bytes(bytes);
337
338 assert_eq!(bytes[6] >> 4, 4);
339 assert!(matches!(bytes[8] >> 6, 0b10));
340 assert_eq!(uuid.as_bytes(), bytes);
341 }
342
343 #[cfg(all(feature = "simulation", madsim))]
344 #[rstest]
345 fn test_new_bytes_is_deterministic_in_virtual_time_runtime() {
346 let generate = |seed| {
347 let runtime =
348 madsim::runtime::Runtime::with_seed_and_config(seed, madsim::Config::default());
349 runtime.block_on(async { (0..4).map(|_| UUID4::new_bytes()).collect::<Vec<_>>() })
350 };
351
352 let first = generate(42);
353 let repeated = generate(42);
354 let different = generate(43);
355
356 assert_eq!(first, repeated);
357 assert_ne!(first, different);
358 }
359
360 #[rstest]
361 fn test_uuid_format() {
362 let uuid = UUID4::new();
363 let bytes = uuid.value;
364
365 assert_eq!(bytes[36], 0);
367
368 assert_eq!(bytes[8] as char, '-');
370 assert_eq!(bytes[13] as char, '-');
371 assert_eq!(bytes[18] as char, '-');
372 assert_eq!(bytes[23] as char, '-');
373
374 let s = uuid.to_string();
375 assert_eq!(s.chars().nth(14).unwrap(), '4');
376 }
377
378 #[rstest]
379 fn test_format_uuid4_bytes_golden() {
380 let bytes = [
381 0x2d, 0x89, 0x66, 0x6b, 0x1a, 0x1e, 0x4a, 0x75, 0xb1, 0x93, 0x4e, 0xb3, 0xb4, 0x54,
382 0xc7, 0x57,
383 ];
384
385 let formatted = format_uuid4_bytes(bytes);
386 let text = CStr::from_bytes_with_nul(&formatted)
387 .unwrap()
388 .to_str()
389 .unwrap();
390
391 assert_eq!(text, "2d89666b-1a1e-4a75-b193-4eb3b454c757");
392 assert_eq!(formatted[36], 0);
393 }
394
395 #[rstest]
396 #[should_panic(expected = "UUID is not version 4")]
397 fn test_from_str_with_non_version_4_uuid_panics() {
398 let uuid_string = "6ba7b810-9dad-11d1-80b4-00c04fd430c8"; let _ = UUID4::from(uuid_string);
400 }
401
402 #[rstest]
403 fn test_case_insensitive_parsing() {
404 let upper = "2D89666B-1A1E-4A75-B193-4EB3B454C757";
405 let lower = "2d89666b-1a1e-4a75-b193-4eb3b454c757";
406 let uuid_upper = UUID4::from(upper);
407 let uuid_lower = UUID4::from(lower);
408
409 assert_eq!(uuid_upper, uuid_lower);
410 assert_eq!(uuid_upper.to_string(), lower);
411 }
412
413 #[rstest]
414 #[case("6ba7b810-9dad-11d1-80b4-00c04fd430c8")] #[case("000001f5-8fa9-21d1-9df3-00e098032b8c")] #[case("3d813cbb-47fb-32ba-91df-831e1593ac29")] #[case("fb4f37c1-4ba3-5173-9812-2b90e76a06f7")] #[should_panic(expected = "UUID is not version 4")]
419 fn test_invalid_version(#[case] uuid_string: &str) {
420 let _ = UUID4::from(uuid_string);
421 }
422
423 #[rstest]
424 #[should_panic(expected = "UUID is not RFC 4122 variant")]
425 fn test_non_rfc4122_variant() {
426 let uuid = "550e8400-e29b-41d4-0000-446655440000";
428 let _ = UUID4::from(uuid);
429 }
430
431 #[rstest]
432 #[case("")] #[case("not-a-uuid-at-all")] #[case("6ba7b810-9dad-11d1-80b4")] #[case("6ba7b810-9dad-11d1-80b4-00c04fd430c8-extra")] #[case("6ba7b810-9dad-11d1-80b4=00c04fd430c8")] #[case("6ba7b81019dad111d180b400c04fd430c8")] #[case("6ba7b810-9dad-11d1-80b4-00c04fd430")] #[case("6ba7b810-9dad-11d1-80b4-00c04fd430cg")] fn test_invalid_uuid_cases(#[case] invalid_uuid: &str) {
441 assert!(UUID4::from_str(invalid_uuid).is_err());
442 }
443
444 #[rstest]
445 fn test_default() {
446 let uuid: UUID4 = UUID4::default();
447 let uuid_string = uuid.to_string();
448 let uuid_parsed = Uuid::parse_str(&uuid_string).unwrap();
449 assert_eq!(uuid_parsed.get_version().unwrap(), uuid::Version::Random);
450 }
451
452 #[rstest]
453 fn test_from_str() {
454 let uuid_string = "2d89666b-1a1e-4a75-b193-4eb3b454c757";
455 let uuid = UUID4::from(uuid_string);
456 let result_string = uuid.to_string();
457 let result_parsed = Uuid::parse_str(&result_string).unwrap();
458 let expected_parsed = Uuid::parse_str(uuid_string).unwrap();
459 assert_eq!(result_parsed, expected_parsed);
460 }
461
462 #[rstest]
463 fn test_from_string() {
464 let uuid = UUID4::from("2d89666b-1a1e-4a75-b193-4eb3b454c757".to_string());
465 assert_eq!(uuid.as_str(), "2d89666b-1a1e-4a75-b193-4eb3b454c757");
466 }
467
468 #[rstest]
469 fn test_from_uuid() {
470 let original = uuid::Uuid::new_v4();
471 let uuid4 = UUID4::from(original);
472 assert_eq!(uuid4.to_string(), original.to_string());
473 }
474
475 #[rstest]
476 fn test_into_uuid_roundtrip() {
477 let uuid_string = "2d89666b-1a1e-4a75-b193-4eb3b454c757";
478 let uuid4 = UUID4::from(uuid_string);
479 let uuid = uuid::Uuid::from(uuid4);
480 assert_eq!(uuid.to_string(), uuid_string);
481 assert_eq!(UUID4::from(uuid).as_str(), uuid_string);
482 }
483
484 #[rstest]
485 fn test_equality() {
486 let uuid1 = UUID4::from("2d89666b-1a1e-4a75-b193-4eb3b454c757");
487 let uuid2 = UUID4::from("46922ecb-4324-4e40-a56c-841e0d774cef");
488 assert_eq!(uuid1, uuid1);
489 assert_ne!(uuid1, uuid2);
490 }
491
492 #[rstest]
493 fn test_debug() {
494 let uuid_string = "2d89666b-1a1e-4a75-b193-4eb3b454c757";
495 let uuid = UUID4::from(uuid_string);
496 assert_eq!(format!("{uuid:?}"), format!("UUID4({uuid_string})"));
497 }
498
499 #[rstest]
500 fn test_display() {
501 let uuid_string = "2d89666b-1a1e-4a75-b193-4eb3b454c757";
502 let uuid = UUID4::from(uuid_string);
503 assert_eq!(format!("{uuid}"), uuid_string);
504 }
505
506 #[rstest]
507 fn test_to_cstr() {
508 let uuid = UUID4::new();
509 let cstr = uuid.to_cstr();
510
511 assert_eq!(cstr.to_str().unwrap(), uuid.to_string());
512 assert_eq!(cstr.to_bytes_with_nul()[36], 0);
513 }
514
515 #[rstest]
516 fn test_as_str() {
517 let uuid = UUID4::new();
518 let s = uuid.as_str();
519
520 assert_eq!(s, uuid.to_string());
521 assert_eq!(s.len(), 36);
522 }
523
524 #[rstest]
525 fn test_hash_consistency() {
526 let uuid = UUID4::new();
527
528 let mut hasher1 = DefaultHasher::new();
529 let mut hasher2 = DefaultHasher::new();
530
531 uuid.hash(&mut hasher1);
532 uuid.hash(&mut hasher2);
533
534 assert_eq!(hasher1.finish(), hasher2.finish());
535 }
536
537 #[rstest]
538 fn test_serialize_json() {
539 let uuid_string = "2d89666b-1a1e-4a75-b193-4eb3b454c757";
540 let uuid = UUID4::from(uuid_string);
541
542 let serialized = serde_json::to_string(&uuid).unwrap();
543 let expected_json = format!("\"{uuid_string}\"");
544 assert_eq!(serialized, expected_json);
545 }
546
547 #[rstest]
548 fn test_deserialize_json() {
549 let uuid_string = "2d89666b-1a1e-4a75-b193-4eb3b454c757";
550 let serialized = format!("\"{uuid_string}\"");
551
552 let deserialized: UUID4 = serde_json::from_str(&serialized).unwrap();
553 assert_eq!(deserialized.to_string(), uuid_string);
554 }
555
556 #[rstest]
557 fn test_deserialize_from_owned_value() {
558 let uuid_string = "2d89666b-1a1e-4a75-b193-4eb3b454c757";
559 let value = serde_json::Value::String(uuid_string.to_string());
560
561 let deserialized: UUID4 = serde_json::from_value(value).unwrap();
562 assert_eq!(deserialized.to_string(), uuid_string);
563 }
564
565 #[rstest]
566 fn test_serialize_deserialize_round_trip() {
567 let uuid = UUID4::new();
568
569 let serialized = serde_json::to_string(&uuid).unwrap();
570 let deserialized: UUID4 = serde_json::from_str(&serialized).unwrap();
571
572 assert_eq!(uuid, deserialized);
573 }
574
575 #[rstest]
576 fn test_as_bytes() {
577 let uuid_string = "2d89666b-1a1e-4a75-b193-4eb3b454c757";
578 let uuid = UUID4::from(uuid_string);
579
580 let bytes = uuid.as_bytes();
581 assert_eq!(bytes.len(), 16);
582
583 let reconstructed = Uuid::from_bytes(bytes);
585 assert_eq!(reconstructed.to_string(), uuid_string);
586
587 assert_eq!(reconstructed.get_version().unwrap(), uuid::Version::Random);
589 }
590
591 #[rstest]
592 fn test_as_bytes_round_trip() {
593 let uuid1 = UUID4::new();
594 let bytes = uuid1.as_bytes();
595 let uuid2 = UUID4::from(Uuid::from_bytes(bytes));
596
597 assert_eq!(uuid1, uuid2);
598 }
599
600 #[rstest]
601 fn test_from_bytes_basic() {
602 let bytes = [
604 0x2d, 0x89, 0x66, 0x6b, 0x1a, 0x1e, 0x4a, 0x75, 0xb1, 0x93, 0x4e, 0xb3, 0xb4, 0x54,
605 0xc7, 0x57,
606 ];
607 let uuid = UUID4::from_bytes(bytes);
608 assert_eq!(uuid.to_string(), "2d89666b-1a1e-4a75-b193-4eb3b454c757");
609 assert_eq!(uuid.as_bytes(), bytes);
610 }
611
612 #[rstest]
613 fn test_from_bytes_normalizes_version() {
614 let mut bytes = [0u8; 16];
616 bytes[6] = 0x1a; bytes[8] = 0x80; let uuid = UUID4::from_bytes(bytes);
619 assert_eq!(&uuid.to_string()[14..15], "4");
620 let parsed = Uuid::parse_str(uuid.as_str()).unwrap();
621 assert_eq!(parsed.get_version(), Some(uuid::Version::Random));
622 }
623
624 #[rstest]
625 fn test_from_bytes_normalizes_variant() {
626 let mut bytes = [0u8; 16];
628 bytes[6] = 0x40; bytes[8] = 0x00; let uuid = UUID4::from_bytes(bytes);
631 let parsed = Uuid::parse_str(uuid.as_str()).unwrap();
632 assert_eq!(parsed.get_variant(), uuid::Variant::RFC4122);
633 }
634
635 #[rstest]
636 fn test_from_bytes_all_zero_is_valid_v4() {
637 let uuid = UUID4::from_bytes([0u8; 16]);
638 assert_eq!(uuid.to_string(), "00000000-0000-4000-8000-000000000000");
641 }
642
643 #[rstest]
644 fn test_from_bytes_all_ones_is_valid_v4() {
645 let uuid = UUID4::from_bytes([0xFFu8; 16]);
646 let parsed = Uuid::parse_str(uuid.as_str()).unwrap();
647 assert_eq!(parsed.get_version(), Some(uuid::Version::Random));
648 assert_eq!(parsed.get_variant(), uuid::Variant::RFC4122);
649 }
650
651 #[rstest]
652 fn test_from_bytes_round_trip() {
653 let original = UUID4::new();
656 let bytes = original.as_bytes();
657 let reconstructed = UUID4::from_bytes(bytes);
658 assert_eq!(original, reconstructed);
659 }
660
661 #[rstest]
662 #[case("\"not-a-uuid\"")] #[case("\"6ba7b810-9dad-11d1-80b4-00c04fd430c8\"")] #[case("\"\"")] fn test_deserialize_invalid_uuid_returns_error(#[case] json: &str) {
666 let result: Result<UUID4, _> = serde_json::from_str(json);
667 assert!(result.is_err());
668 }
669
670 fn uuid4_strategy() -> impl Strategy<Value = UUID4> {
671 any::<[u8; 16]>().prop_map(UUID4::from_bytes)
674 }
675
676 proptest! {
677 #[rstest]
678 fn prop_uuid4_string_roundtrip(uuid in uuid4_strategy()) {
679 let s = uuid.to_string();
680 let parsed = UUID4::from_str(&s);
681 prop_assert!(parsed.is_ok(), "Failed to parse UUID string: {}", s);
682 prop_assert_eq!(parsed.unwrap(), uuid, "String round-trip failed");
683 }
684
685 #[rstest]
686 fn prop_uuid4_serde_roundtrip(uuid in uuid4_strategy()) {
687 let serialized = serde_json::to_string(&uuid).unwrap();
688 let deserialized: UUID4 = serde_json::from_str(&serialized).unwrap();
689 prop_assert_eq!(deserialized, uuid, "Serde JSON round-trip failed");
690 }
691
692 #[rstest]
693 fn prop_uuid4_rfc4122_compliance(uuid in uuid4_strategy()) {
694 let s = uuid.to_string();
695 let bytes = uuid.value;
696
697 prop_assert_eq!(s.len(), 36);
699 prop_assert_eq!(bytes[36], 0, "Missing null terminator at index 36");
700
701 prop_assert_eq!(bytes[8] as char, '-');
703 prop_assert_eq!(bytes[13] as char, '-');
704 prop_assert_eq!(bytes[18] as char, '-');
705 prop_assert_eq!(bytes[23] as char, '-');
706
707 prop_assert_eq!(&s[14..15], "4", "Version digit must be 4");
709
710 let variant_char = s.chars().nth(19).unwrap().to_ascii_lowercase();
713 prop_assert!(
714 matches!(variant_char, '8' | '9' | 'a' | 'b'),
715 "Invalid variant character: {}", variant_char
716 );
717 }
718
719 #[rstest]
720 fn prop_uuid4_as_bytes_consistency(uuid in uuid4_strategy()) {
721 let bytes = uuid.as_bytes();
722 let reconstructed = uuid::Uuid::from_bytes(bytes);
723 prop_assert_eq!(reconstructed.to_string(), uuid.to_string(), "Byte reconstruction mismatch");
724 }
725
726 #[rstest]
727 fn prop_uuid4_equality_and_hashing(uuid in uuid4_strategy()) {
728 let equivalent = uuid;
729 let mut first_hasher = DefaultHasher::new();
730 let mut second_hasher = DefaultHasher::new();
731 uuid.hash(&mut first_hasher);
732 equivalent.hash(&mut second_hasher);
733
734 prop_assert_eq!(uuid, equivalent);
735 prop_assert_eq!(first_hasher.finish(), second_hasher.finish());
736 }
737
738 #[rstest]
739 fn prop_uuid4_from_str_never_panics(s: String) {
740 let _ = UUID4::from_str(&s);
742 }
743
744 #[rstest]
745 fn prop_from_bytes_always_yields_v4(bytes in any::<[u8; 16]>()) {
746 let uuid = UUID4::from_bytes(bytes);
749 let parsed = uuid::Uuid::parse_str(uuid.as_str()).unwrap();
750 prop_assert_eq!(parsed.get_version(), Some(uuid::Version::Random));
751 prop_assert_eq!(parsed.get_variant(), uuid::Variant::RFC4122);
752 }
753
754 #[rstest]
755 fn prop_from_bytes_as_bytes_roundtrip(bytes in any::<[u8; 16]>()) {
756 let mut expected = bytes;
759 expected[6] = (expected[6] & 0x0F) | 0x40;
760 expected[8] = (expected[8] & 0x3F) | 0x80;
761 let uuid = UUID4::from_bytes(bytes);
762 prop_assert_eq!(uuid.as_bytes(), expected);
763 }
764 }
765}