1#![cfg_attr(not(any(test, feature = "std")), no_std)]
3#![cfg_attr(docsrs, feature(doc_cfg))]
4use core::{
5 convert::TryInto,
6 fmt,
7 str::{from_utf8_unchecked_mut, FromStr},
8};
9
10use hex_simd::{decode_inplace, AsciiCase::Lower, Out};
11use md5::{Digest, Md5};
12#[cfg(feature = "getrandom")]
13use rand_chacha::rand_core::OsRng;
14use rand_chacha::{
15 rand_core::{RngCore, SeedableRng},
16 ChaChaRng,
17};
18#[cfg(feature = "serde")]
19use serde::{Deserialize, Serialize};
20use sha1::Sha1;
21
22const UUID_STR_LENGTH: usize = 36;
23const UUID_URN_LENGTH: usize = 45;
24const UUID_BRACED_LENGTH: usize = 38;
25const UUID_SIMPLE_LENGTH: usize = 32;
26const UUID_URN: &str = "urn:uuid:";
27const UUID_URN_PREFIX: usize = UUID_URN.len();
28
29pub const NAMESPACE_DNS: Uuid = Uuid::from_bytes([
31 107, 167, 184, 16, 157, 173, 17, 209, 128, 180, 0, 192, 79, 212, 48, 200,
32]);
33
34pub const NAMESPACE_URL: Uuid = Uuid::from_bytes([
36 107, 167, 184, 17, 157, 173, 17, 209, 128, 180, 0, 192, 79, 212, 48, 200,
37]);
38
39pub const NAMESPACE_OID: Uuid = Uuid::from_bytes([
41 107, 167, 184, 18, 157, 173, 17, 209, 128, 180, 0, 192, 79, 212, 48, 200,
42]);
43
44pub const NAMESPACE_X500: Uuid = Uuid::from_bytes([
46 107, 167, 184, 20, 157, 173, 17, 209, 128, 180, 0, 192, 79, 212, 48, 200,
47]);
48
49pub type Bytes = [u8; 16];
51
52#[derive(Debug, Clone)]
54pub struct Rng(ChaChaRng);
55
56impl Rng {
57 #[cfg(feature = "getrandom")]
59 #[cfg_attr(docsrs, doc(cfg(feature = "getrandom")))]
60 #[inline]
61 pub fn new() -> Self {
62 Self(ChaChaRng::from_rng(OsRng).unwrap())
63 }
64
65 #[inline]
67 pub fn from_seed(seed: [u8; 32]) -> Self {
68 Self(ChaChaRng::from_seed(seed))
69 }
70
71 #[inline]
73 fn fill_bytes(&mut self, dest: &mut [u8]) {
74 self.0.fill_bytes(dest)
75 }
76}
77
78#[cfg_attr(docsrs, doc(cfg(feature = "getrandom")))]
79#[cfg(feature = "getrandom")]
80impl Default for Rng {
81 #[inline]
82 fn default() -> Self {
83 Self::new()
84 }
85}
86
87#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
89#[non_exhaustive]
90pub enum Variant {
91 Ncs,
93
94 Rfc4122,
96
97 Microsoft,
99
100 Reserved,
102}
103
104impl fmt::Display for Variant {
105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 match self {
107 Variant::Ncs => write!(f, "Ncs"),
108 Variant::Rfc4122 => write!(f, "Rfc4122"),
109 Variant::Microsoft => write!(f, "Microsoft"),
110 Variant::Reserved => write!(f, "Reserved"),
111 }
112 }
113}
114
115#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
117#[non_exhaustive]
118pub enum Version {
119 Nil = 0,
121
122 Time,
124
125 Dce,
127
128 Md5,
130
131 Random,
133
134 Sha1,
136
137 #[cfg(feature = "experimental_uuid")]
139 #[cfg_attr(docsrs, doc(cfg(feature = "experimental_uuid")))]
140 Database,
141
142 #[cfg(feature = "experimental_uuid")]
144 #[cfg_attr(docsrs, doc(cfg(feature = "experimental_uuid")))]
145 UnixTime,
146
147 #[cfg(feature = "experimental_uuid")]
149 #[cfg_attr(docsrs, doc(cfg(feature = "experimental_uuid")))]
150 Vendor,
151
152 Reserved,
154}
155
156impl fmt::Display for Version {
157 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
158 match self {
159 Version::Nil => write!(f, "Nil"),
160 Version::Time => write!(f, "Time"),
161 Version::Dce => write!(f, "Dce"),
162 Version::Md5 => write!(f, "Md5"),
163 Version::Random => write!(f, "Random"),
164 Version::Sha1 => write!(f, "Sha1"),
165
166 #[cfg(feature = "experimental_uuid")]
167 Version::Database => write!(f, "Database"),
168 #[cfg(feature = "experimental_uuid")]
169 Version::UnixTime => write!(f, "UnixTime"),
170 #[cfg(feature = "experimental_uuid")]
171 Version::Vendor => write!(f, "Vendor"),
172
173 Version::Reserved => write!(f, "Reserved"),
174 }
175 }
176}
177
178#[derive(Debug)]
180pub struct ParseUuidError;
181
182impl fmt::Display for ParseUuidError {
183 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184 write!(f, "ParseUuidError")
185 }
186}
187
188#[cfg(any(test, feature = "std"))]
189#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
190impl std::error::Error for ParseUuidError {}
191
192#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Default)]
202#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(transparent))]
203#[repr(transparent)]
204pub struct Uuid(Bytes);
205
206impl Uuid {
207 #[inline]
209 fn set_version(&mut self, ver: Version) {
210 self.0[6] = (self.0[6] & 0xF) | ((ver as u8) << 4);
212 }
213
214 #[inline]
222 fn set_variant(&mut self, ver: Variant) {
223 let byte = self.0[8];
224 self.0[8] = match ver {
225 Variant::Ncs => byte & 0x7F,
227 Variant::Rfc4122 => (byte & 0x3F) | 0x80,
229 Variant::Microsoft => (byte & 0x1F) | 0xC0,
231 Variant::Reserved => byte | 0xE0,
233 }
234 }
235
236 #[inline]
238 const fn swap_endian(mut self) -> Self {
239 let (a1, a2, a3, a4) = (self.0[0], self.0[1], self.0[2], self.0[3]);
241 self.0[0] = a4;
242 self.0[1] = a3;
243 self.0[2] = a2;
244 self.0[3] = a1;
245
246 let (a1, a2) = (self.0[4], self.0[5]);
247 self.0[4] = a2;
248 self.0[5] = a1;
249
250 let (a1, a2) = (self.0[6], self.0[7]);
251 self.0[6] = a2;
252 self.0[7] = a1;
253
254 self
255 }
256}
257
258impl Uuid {
259 #[inline]
261 pub const fn nil() -> Self {
262 Uuid([0; 16])
263 }
264
265 #[inline]
267 #[cfg(feature = "experimental_uuid")]
268 #[cfg_attr(docsrs, doc(cfg(feature = "experimental_uuid")))]
269 pub const fn max() -> Self {
270 Uuid([1; 16])
271 }
272
273 #[inline]
275 pub const fn from_bytes(bytes: Bytes) -> Self {
276 Self(bytes)
277 }
278
279 #[inline]
281 pub const fn to_bytes(self) -> Bytes {
282 self.0
283 }
284
285 #[inline]
300 pub const fn from_bytes_me(bytes: Bytes) -> Self {
301 Self(bytes).swap_endian()
302 }
303
304 #[inline]
308 pub const fn to_bytes_me(self) -> Bytes {
309 self.swap_endian().to_bytes()
310 }
311
312 #[inline]
314 pub const fn is_nil(self) -> bool {
315 u128::from_ne_bytes(self.0) == 0
318 }
319
320 #[inline]
327 pub const fn variant(self) -> Variant {
328 let byte = (self.0[8] >> 5) & 0b111;
330
331 match (
333 byte >> 2 & 1 == 1,
335 byte >> 1 & 1 == 1,
337 byte & 1 == 1,
339 ) {
340 (false, ..) => Variant::Ncs,
341 (true, false, ..) => Variant::Rfc4122,
342 (true, true, false) => Variant::Microsoft,
343 (true, true, true) => Variant::Reserved,
344 }
345 }
346
347 #[inline]
360 pub const fn version(self) -> Version {
361 match (
363 self.0[6] >> 7 & 1 == 1,
364 self.0[6] >> 6 & 1 == 1,
365 self.0[6] >> 5 & 1 == 1,
366 self.0[6] >> 4 & 1 == 1,
367 ) {
368 (false, false, false, false) => Version::Nil,
369 (false, false, false, true) => Version::Time,
370 (false, false, true, false) => Version::Dce,
371 (false, false, true, true) => Version::Md5,
372 (false, true, false, false) => Version::Random,
373 (false, true, false, true) => Version::Sha1,
374
375 #[cfg(feature = "experimental_uuid")]
376 (false, true, true, false) => Version::Database,
377
378 #[cfg(feature = "experimental_uuid")]
379 (false, true, true, true) => Version::UnixTime,
380
381 #[cfg(feature = "experimental_uuid")]
382 (true, false, false, false) => Version::Vendor,
383
384 _ => Version::Reserved,
385 }
386 }
387
388 #[inline]
395 pub const fn timestamp(self) -> u64 {
396 match self.version() {
397 #[cfg(feature = "experimental_uuid")]
398 Version::Database => u64::from_be_bytes([
399 self.0[6] & 0xF,
401 self.0[7],
402 self.0[4],
403 self.0[5],
404 self.0[0],
405 self.0[1],
406 self.0[2],
407 self.0[3],
408 ]),
409 _ => u64::from_be_bytes([
412 self.0[6] & 0xF,
414 self.0[7],
415 self.0[4],
416 self.0[5],
417 self.0[0],
418 self.0[1],
419 self.0[2],
420 self.0[3],
421 ]),
422 }
423 }
424
425 #[inline]
432 pub const fn clock_sequence(self) -> u16 {
433 u16::from_be_bytes([
434 self.0[8] & 0x3F,
437 self.0[9],
438 ])
439 }
440
441 #[inline]
443 pub const fn node(self) -> [u8; 6] {
444 [
445 self.0[10], self.0[11], self.0[12], self.0[13], self.0[14], self.0[15],
446 ]
447 }
448
449 pub fn to_str(self, buf: &mut [u8; 36]) -> &mut str {
498 buf[8] = b'-';
500 buf[13] = b'-';
501 buf[18] = b'-';
502 buf[23] = b'-';
503
504 let bytes = self.to_bytes();
505
506 let time_low = &bytes[..4];
507 let time_mid = &bytes[4..6];
508 let time_hi_and_version = &bytes[6..8];
509 let clock_seq_hi_and_reserved = &bytes[8..9];
510 let clock_seq_low = &bytes[9..10];
511 let node = &bytes[10..];
512
513 let _ = hex_simd::encode(time_low, Out::from_slice(&mut buf[..8]), Lower);
515 let _ = hex_simd::encode(time_mid, Out::from_slice(&mut buf[9..13]), Lower);
516 let _ = hex_simd::encode(
517 time_hi_and_version,
518 Out::from_slice(&mut buf[14..18]),
519 Lower,
520 );
521 let _ = hex_simd::encode(
522 clock_seq_hi_and_reserved,
523 Out::from_slice(&mut buf[19..21]),
524 Lower,
525 );
526 let _ = hex_simd::encode(clock_seq_low, Out::from_slice(&mut buf[21..23]), Lower);
527 let _ = hex_simd::encode(node, Out::from_slice(&mut buf[24..]), Lower);
528
529 debug_assert!(buf.is_ascii(), "BUG: Invalid ASCII in nuuid::Uuid::to_str");
530 unsafe { from_utf8_unchecked_mut(buf) }
533 }
534
535 #[inline]
540 pub fn to_urn(self, buf: &mut [u8; 45]) -> &mut str {
541 buf[..UUID_URN_PREFIX].copy_from_slice(UUID_URN.as_bytes());
542 self.to_str((&mut buf[UUID_URN_PREFIX..]).try_into().unwrap());
543 core::str::from_utf8_mut(buf).expect("BUG: Invalid UTF8")
544 }
545
546 #[inline]
548 pub fn to_str_upper(self, buf: &mut [u8; 36]) -> &mut str {
549 let s = self.to_str(buf);
550 s.make_ascii_uppercase();
551 s
552 }
553
554 #[inline]
556 pub fn to_urn_upper(self, buf: &mut [u8; 45]) -> &mut str {
557 let s = self.to_urn(buf);
558 s[UUID_URN_PREFIX..].make_ascii_uppercase();
559 s
560 }
561}
562
563impl Uuid {
564 pub fn parse(s: &str) -> Result<Self, ParseUuidError> {
590 if !s.is_ascii() {
592 return Err(ParseUuidError);
593 }
594
595 let s = match s.len() {
596 UUID_URN_LENGTH => &s[UUID_URN_PREFIX..],
597 UUID_BRACED_LENGTH => &s[1..s.len() - 1],
598 UUID_STR_LENGTH => s,
599 UUID_SIMPLE_LENGTH => {
600 return Ok(Uuid::from_bytes(
601 u128::from_str_radix(s, 16)
602 .map_err(|_| ParseUuidError)?
603 .to_be_bytes(),
604 ));
605 }
606 _ => return Err(ParseUuidError),
607 };
608 let s = s.as_bytes();
609
610 let mut raw = [0; UUID_SIMPLE_LENGTH];
611 raw[20..].copy_from_slice(&s[24..]);
625
626 raw[16..20].copy_from_slice(&s[19..23]);
628
629 raw[12..16].copy_from_slice(&s[14..18]);
631
632 raw[8..12].copy_from_slice(&s[9..13]);
634
635 raw[..8].copy_from_slice(&s[..8]);
637
638 let x = decode_inplace(&mut raw).map_err(|_| ParseUuidError)?;
639 Ok(Uuid::from_bytes(x.try_into().map_err(|_| ParseUuidError)?))
640 }
641
642 pub fn parse_me(s: &str) -> Result<Self, ParseUuidError> {
652 Uuid::from_str(s).map(Uuid::swap_endian)
653 }
654
655 #[cfg(feature = "getrandom")]
668 #[cfg_attr(docsrs, doc(cfg(feature = "getrandom")))]
669 #[inline]
670 pub fn new_v4() -> Self {
671 let mut uuid = Uuid::nil();
672 OsRng.fill_bytes(&mut uuid.0);
673 uuid.set_variant(Variant::Rfc4122);
674 uuid.set_version(Version::Random);
675 uuid
676 }
677
678 #[inline]
698 pub fn new_v4_rng(rng: &mut Rng) -> Self {
699 let mut uuid = Uuid::nil();
700 rng.fill_bytes(&mut uuid.0);
701 uuid.set_variant(Variant::Rfc4122);
702 uuid.set_version(Version::Random);
703 uuid
704 }
705
706 #[inline]
720 pub fn new_v3(namespace: Uuid, name: &[u8]) -> Self {
721 let mut hasher = Md5::new();
722 hasher.update(namespace.to_bytes());
723 hasher.update(name);
724 let mut uuid = Uuid::from_bytes(hasher.finalize().into());
725 uuid.set_version(Version::Md5);
726 uuid.set_variant(Variant::Rfc4122);
727 uuid
728 }
729
730 #[inline]
739 pub fn new_v5(namespace: Uuid, name: &[u8]) -> Self {
740 let mut hasher = Sha1::new();
741 hasher.update(namespace.to_bytes());
742 hasher.update(name);
743 let mut uuid = Uuid::from_bytes(hasher.finalize()[..16].try_into().unwrap());
744 uuid.set_version(Version::Sha1);
745 uuid.set_variant(Variant::Rfc4122);
746 uuid
747 }
748
749 #[inline]
764 pub fn new_v1(timestamp: u64, counter: u16, node: [u8; 6]) -> Self {
765 let timestamp = timestamp.to_be_bytes();
766 let counter = counter.to_be_bytes();
767 Uuid::from_bytes([
768 timestamp[4],
770 timestamp[5],
771 timestamp[6],
772 timestamp[7],
773 timestamp[2],
775 timestamp[3],
776 (timestamp[0] & 0xF) | (1u8 << 4),
778 timestamp[1],
779 (counter[0] & 0x3F) | 0x80,
781 counter[1],
782 node[0],
784 node[1],
785 node[2],
786 node[3],
787 node[4],
788 node[5],
789 ])
790 }
791
792 #[inline]
805 #[cfg(feature = "experimental_uuid")]
806 #[cfg_attr(docsrs, doc(cfg(feature = "experimental_uuid")))]
807 pub fn new_v6(timestamp: u64, counter: u16, node: [u8; 6]) -> Self {
808 let timestamp = (timestamp << 4).to_be_bytes();
811 let counter = counter.to_be_bytes();
812
813 Uuid::from_bytes([
814 timestamp[0],
816 timestamp[1],
817 timestamp[2],
818 timestamp[3],
819 timestamp[4],
821 timestamp[5],
822 (timestamp[6] >> 4) | (6u8 << 4),
824 timestamp[7],
825 (counter[0] & 0x3F) | 0x80,
827 counter[1],
828 node[0],
830 node[1],
831 node[2],
832 node[3],
833 node[4],
834 node[5],
835 ])
836 }
837
838 #[inline]
851 #[cfg(feature = "experimental_uuid")]
852 #[cfg_attr(docsrs, doc(cfg(feature = "experimental_uuid")))]
853 pub fn new_v7(timestamp: u64, rand_a: u16, rand_b: u64) -> Self {
854 let timestamp = (timestamp << 16).to_be_bytes();
857 let rand_a = rand_a.to_be_bytes();
858 let rand_b = rand_b.to_be_bytes();
859
860 Uuid::from_bytes([
861 timestamp[0],
863 timestamp[1],
864 timestamp[2],
865 timestamp[3],
866 timestamp[4],
867 timestamp[5],
868 (rand_a[0] & 0xF) | (7u8 << 4),
870 rand_a[1],
871 (rand_b[0] & 0x3F) | 0x80,
873 rand_b[1],
874 rand_b[2],
875 rand_b[3],
876 rand_b[4],
877 rand_b[5],
878 rand_b[6],
879 rand_b[7],
880 ])
881 }
882
883 #[inline]
895 #[cfg(feature = "experimental_uuid")]
896 #[cfg_attr(docsrs, doc(cfg(feature = "experimental_uuid")))]
897 pub fn new_v8(bytes: Bytes) -> Self {
898 let mut uuid = Uuid::from_bytes(bytes);
899 uuid.set_variant(Variant::Rfc4122);
900 uuid.set_version(Version::Vendor);
901 uuid
902 }
903}
904
905impl FromStr for Uuid {
907 type Err = ParseUuidError;
908
909 fn from_str(s: &str) -> Result<Self, Self::Err> {
911 Uuid::parse(s)
912 }
913}
914
915impl fmt::Display for Uuid {
925 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
926 write!(f, "{:X}", self)
927 }
928}
929
930impl fmt::Debug for Uuid {
947 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
948 if f.alternate() {
949 write!(
950 f,
951 r#"Uuid({:X}) {{
952 Version: {}({}),
953 Variant: {}({}),
954}}"#,
955 self,
956 self.version(),
957 self.version() as u8,
958 self.variant(),
959 self.variant() as u8
960 )
961 } else {
962 write!(f, "Uuid({:X})", self)
963 }
964 }
965}
966
967impl fmt::LowerHex for Uuid {
980 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
981 if f.alternate() {
982 write!(f, "{}", UUID_URN)?;
983 }
984 let mut buf = [0; 36];
985 let s = self.to_str(&mut buf);
986 write!(f, "{}", s)
987 }
988}
989
990impl fmt::UpperHex for Uuid {
1003 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1004 if f.alternate() {
1005 write!(f, "{}", UUID_URN)?;
1006 }
1007 let mut buf = [0; 36];
1008 write!(f, "{}", self.to_str_upper(&mut buf))
1009 }
1010}
1011
1012impl AsRef<[u8]> for Uuid {
1013 #[inline]
1014 fn as_ref(&self) -> &[u8] {
1015 &self.0
1016 }
1017}
1018
1019impl AsRef<[u8; 16]> for Uuid {
1020 #[inline]
1021 fn as_ref(&self) -> &[u8; 16] {
1022 &self.0
1023 }
1024}
1025
1026#[cfg(test)]
1027mod tests {
1028 use super::*;
1029
1030 const UUID_NIL: &str = "00000000-0000-0000-0000-000000000000";
1031 const UUID_V4: &str = "662aa7c7-7598-4d56-8bcc-a72c30f998a2";
1032 const UUID_V4_SIMPLE: &str = "662aa7c775984d568bcca72c30f998a2";
1033 const UUID_V4_BRACED: &str = "{662aa7c7-7598-4d56-8bcc-a72c30f998a2}";
1034 const UUID_V4_URN: &str = "urn:uuid:662aa7c7-7598-4d56-8bcc-a72c30f998a2";
1035 const UUID_V4_URN_UPPER: &str = "urn:uuid:662AA7C7-7598-4D56-8BCC-A72C30F998A2";
1036 const RAW: [u8; 16] = [
1037 102, 42, 167, 199, 117, 152, 77, 86, 139, 204, 167, 44, 48, 249, 152, 162,
1038 ];
1039
1040 fn name(fun: fn(Uuid, &[u8]) -> Uuid, ver: Version) {
1041 let namespace = Uuid::new_v4();
1042 let namespace2 = Uuid::new_v4();
1043 let uuid1 = fun(namespace, b"test");
1044 let uuid2 = fun(namespace, b"test");
1045 assert_eq!(
1046 uuid1, uuid2,
1047 "UUID's from different times with the same name/namespace must be equal"
1048 );
1049
1050 let uuid = fun(namespace, b"Cat");
1051 assert_ne!(
1052 uuid, uuid2,
1053 "UUID's with two different names in the same namespace must NOT be equal"
1054 );
1055
1056 let uuid = fun(namespace2, b"test");
1057 assert_ne!(
1058 uuid, uuid2,
1059 "UUID's with the same names in a different namespace must NOT be equal"
1060 );
1061
1062 assert_eq!(uuid.version(), ver);
1063 assert_eq!(uuid.variant(), Variant::Rfc4122);
1064 }
1065
1066 #[test]
1067 #[cfg(feature = "experimental_uuid")]
1068 fn new_v6() {
1069 const UUID: &str = "1EC9414C-232A-6B00-B3C8-9E6BDECED846";
1071 let (ticks, counter, node) = (138648505420000000, 13256, [158, 107, 222, 206, 216, 70]);
1072
1073 let uuid = Uuid::new_v6(ticks, counter, node);
1074 let uuid_ = Uuid::parse(UUID).unwrap();
1075
1076 assert_eq!(uuid.to_str_upper(&mut [0; 36]), UUID);
1077 assert_eq!(uuid.version(), Version::Database);
1078 assert_eq!(uuid.variant(), Variant::Rfc4122);
1079
1080 assert_eq!(uuid.timestamp(), uuid_.timestamp());
1081 assert_eq!(uuid.clock_sequence(), uuid_.clock_sequence());
1082 assert_eq!(uuid.node()[..], uuid_.node());
1083 }
1084
1085 #[test]
1086 #[cfg(feature = "experimental_uuid")]
1087 fn new_v7() {
1088 const UUID: &str = "017F22E2-79B0-7CC3-98C4-DC0C0C07398F";
1090 let (unix_ts, rand_a, rand_b) = (0x17F22E279B0, 0xCC3, 0x18C4DC0C0C07398F);
1091
1092 let uuid = Uuid::new_v7(unix_ts, rand_a, rand_b);
1093 let uuid_ = Uuid::parse(UUID).unwrap();
1094
1095 assert_eq!(uuid.to_str_upper(&mut [0; 36]), UUID);
1096 assert_eq!(uuid.version(), Version::UnixTime);
1097 assert_eq!(uuid.variant(), Variant::Rfc4122);
1098
1099 assert_eq!(uuid.timestamp(), uuid_.timestamp());
1100 assert_eq!(uuid.clock_sequence(), uuid_.clock_sequence());
1101 assert_eq!(uuid.node()[..], uuid_.node());
1102 }
1103
1104 #[test]
1105 fn time() {
1106 use uuid_::{v1::*, Uuid as Uuid_};
1107 let (ticks, counter, node) = (138788330336896890u64, 8648, *b"world!");
1108
1109 let uuid = Uuid::new_v1(ticks, counter, node);
1110 let uuid_ = Uuid_::new_v1(Timestamp::from_rfc4122(ticks, counter), &node);
1111 assert_eq!(uuid.to_bytes(), *uuid_.as_bytes());
1112 assert_eq!(uuid.version(), Version::Time);
1113 assert_eq!(uuid.variant(), Variant::Rfc4122);
1114
1115 assert_eq!(
1116 uuid.timestamp(),
1117 uuid_.get_timestamp().unwrap().to_rfc4122().0
1118 );
1119 assert_eq!(
1120 uuid.clock_sequence(),
1121 uuid_.get_timestamp().unwrap().to_rfc4122().1
1122 );
1123 assert_eq!(uuid.node()[..], uuid_.as_fields().3[2..]);
1124 }
1125
1126 #[test]
1127 fn md5() {
1128 name(Uuid::new_v3, Version::Md5);
1129 let uuid = Uuid::new_v3(NAMESPACE_DNS, b"www.widgets.com");
1130 assert_eq!(
1131 uuid,
1132 Uuid::from_str("3d813cbb-47fb-32ba-91df-831e1593ac29").unwrap()
1135 )
1136 }
1137
1138 #[test]
1139 fn sha1() {
1140 name(Uuid::new_v5, Version::Sha1)
1141 }
1142
1143 #[test]
1144 fn parse_string() {
1145 let test = &[UUID_V4, UUID_V4_URN, UUID_V4_BRACED, UUID_V4_SIMPLE];
1146 for uuid in test {
1147 println!("Source UUID: {}", uuid);
1148 let uuid = Uuid::from_str(&uuid.to_ascii_lowercase()).unwrap();
1149 println!("Parsed UUID: {}\n", uuid);
1150 assert_eq!(RAW, uuid.to_bytes(), "Parsed UUID bytes don't match");
1151 }
1152
1153 for uuid in test {
1154 println!("Source UUID: {}", uuid);
1155 let uuid = Uuid::from_str(&uuid.to_ascii_uppercase()).unwrap();
1156 println!("Parsed UUID: {}\n", uuid);
1157 assert_eq!(RAW, uuid.to_bytes(), "Parsed UUID bytes don't match");
1158 }
1159 }
1160
1161 #[test]
1162 fn string() {
1163 let uuid = Uuid::from_bytes(RAW);
1164 let mut buf = [0; 45];
1165 assert_eq!(
1166 uuid.to_str((&mut buf[..36]).try_into().unwrap()),
1167 UUID_V4,
1168 "UUID strings didn't match"
1169 );
1170 assert_eq!(
1171 uuid.to_urn(&mut buf),
1172 UUID_V4_URN,
1173 "UUID URN strings didn't match"
1174 );
1175 assert_eq!(
1176 uuid.to_urn_upper(&mut buf),
1177 UUID_V4_URN_UPPER,
1178 "UUID URN upper strings didn't match"
1179 );
1180 assert_eq!(
1181 format!("{:#x}", uuid),
1182 UUID_V4_URN,
1183 "UUID URN Display didn't match"
1184 );
1185 assert_eq!(format!("{:x}", uuid), UUID_V4, "UUID Display didn't match");
1186 assert_eq!(
1187 format!("{}", uuid),
1188 UUID_V4.to_ascii_uppercase(),
1189 "UUID Display didn't match"
1190 );
1191 assert_eq!(
1192 format!("{}", Uuid::nil()),
1193 UUID_NIL,
1194 "Nil UUID Display didn't work!"
1195 );
1196 }
1197
1198 #[test]
1199 fn endian() {
1200 let uuid_be = Uuid::from_bytes(RAW);
1201 assert_eq!(uuid_be.version(), Version::Random);
1202 assert_eq!(uuid_be.variant(), Variant::Rfc4122);
1203
1204 let uuid_le = Uuid::from_bytes_me(uuid_be.to_bytes_me());
1205 assert_eq!(uuid_le.version(), Version::Random);
1206 assert_eq!(uuid_le.variant(), Variant::Rfc4122);
1207
1208 assert_eq!(uuid_le, uuid_be);
1209 assert_ne!(uuid_be.to_bytes_me(), uuid_be.to_bytes());
1210
1211 const UUID: &str = "20169084-b186-884f-b110-3db2c37eb8b5";
1215 let uuid = Uuid::parse_me(UUID).unwrap();
1216 let bad_uuid = Uuid::parse(UUID).unwrap();
1217
1218 assert_ne!(bad_uuid.version(), Version::Random);
1219 assert_eq!(uuid.version(), Version::Random);
1220 assert_eq!(uuid.variant(), Variant::Rfc4122);
1221 assert_ne!(uuid.to_str(&mut [0; 36]), UUID);
1223 }
1224
1225 #[test]
1226 fn info() {
1227 let uuid = Uuid::from_bytes(RAW);
1228 assert_eq!(uuid.version(), Version::Random);
1229 assert_eq!(uuid.variant(), Variant::Rfc4122);
1230 #[cfg(feature = "getrandom")]
1231 {
1232 let uuid = Uuid::new_v4();
1233 assert_eq!(uuid.version(), Version::Random);
1234 assert_eq!(uuid.variant(), Variant::Rfc4122);
1235 }
1236 }
1237}