#![no_std]
#![deny(missing_debug_implementations, missing_docs)]
#![doc(
html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "https://www.rust-lang.org/favicon.ico",
html_root_url = "https://docs.rs/uuid/0.8.1"
)]
#[cfg(any(feature = "std", test))]
#[macro_use]
extern crate std;
#[cfg(all(not(feature = "std"), not(test)))]
#[macro_use]
extern crate core as std;
mod builder;
mod error;
mod parser;
mod prelude;
pub mod adapter;
#[cfg(feature = "v1")]
pub mod v1;
#[cfg(feature = "serde")]
mod serde_support;
#[cfg(feature = "slog")]
mod slog_support;
#[cfg(test)]
mod test_util;
#[cfg(all(
feature = "v3",
any(
not(target_arch = "wasm32"),
all(
target_arch = "wasm32",
any(feature = "stdweb", feature = "wasm-bindgen")
)
)
))]
mod v3;
#[cfg(all(
feature = "v4",
any(
not(target_arch = "wasm32"),
all(
target_arch = "wasm32",
any(feature = "stdweb", feature = "wasm-bindgen")
)
)
))]
mod v4;
#[cfg(all(
feature = "v5",
any(
not(target_arch = "wasm32"),
all(
target_arch = "wasm32",
any(feature = "stdweb", feature = "wasm-bindgen")
)
)
))]
mod v5;
#[cfg(all(windows, feature = "winapi"))]
mod winapi_support;
use crate::std::{fmt, str};
pub use crate::{builder::Builder, error::Error};
pub type Bytes = [u8; 16];
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Version {
Nil = 0,
Mac,
Dce,
Md5,
Random,
Sha1,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Variant {
NCS = 0,
RFC4122,
Microsoft,
Future,
}
#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Uuid(Bytes);
impl Uuid {
pub const NAMESPACE_DNS: Self = Uuid([
0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0,
0x4f, 0xd4, 0x30, 0xc8,
]);
pub const NAMESPACE_OID: Self = Uuid([
0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0,
0x4f, 0xd4, 0x30, 0xc8,
]);
pub const NAMESPACE_URL: Self = Uuid([
0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0,
0x4f, 0xd4, 0x30, 0xc8,
]);
pub const NAMESPACE_X500: Self = Uuid([
0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0,
0x4f, 0xd4, 0x30, 0xc8,
]);
pub fn get_variant(&self) -> Option<Variant> {
match self.as_bytes()[8] {
x if x & 0x80 == 0x00 => Some(Variant::NCS),
x if x & 0xc0 == 0x80 => Some(Variant::RFC4122),
x if x & 0xe0 == 0xc0 => Some(Variant::Microsoft),
x if x & 0xe0 == 0xe0 => Some(Variant::Future),
_ => None,
}
}
pub const fn get_version_num(&self) -> usize {
(self.as_bytes()[6] >> 4) as usize
}
pub fn get_version(&self) -> Option<Version> {
let v = self.as_bytes()[6] >> 4;
match v {
0 if self.is_nil() => Some(Version::Nil),
1 => Some(Version::Mac),
2 => Some(Version::Dce),
3 => Some(Version::Md5),
4 => Some(Version::Random),
5 => Some(Version::Sha1),
_ => None,
}
}
pub fn as_fields(&self) -> (u32, u16, u16, &[u8; 8]) {
let d1 = u32::from(self.as_bytes()[0]) << 24
| u32::from(self.as_bytes()[1]) << 16
| u32::from(self.as_bytes()[2]) << 8
| u32::from(self.as_bytes()[3]);
let d2 =
u16::from(self.as_bytes()[4]) << 8 | u16::from(self.as_bytes()[5]);
let d3 =
u16::from(self.as_bytes()[6]) << 8 | u16::from(self.as_bytes()[7]);
let d4: &[u8; 8] =
unsafe { &*(self.as_bytes()[8..16].as_ptr() as *const [u8; 8]) };
(d1, d2, d3, d4)
}
pub fn to_fields_le(&self) -> (u32, u16, u16, &[u8; 8]) {
let d1 = u32::from(self.as_bytes()[0])
| u32::from(self.as_bytes()[1]) << 8
| u32::from(self.as_bytes()[2]) << 16
| u32::from(self.as_bytes()[3]) << 24;
let d2 =
u16::from(self.as_bytes()[4]) | u16::from(self.as_bytes()[5]) << 8;
let d3 =
u16::from(self.as_bytes()[6]) | u16::from(self.as_bytes()[7]) << 8;
let d4: &[u8; 8] =
unsafe { &*(self.as_bytes()[8..16].as_ptr() as *const [u8; 8]) };
(d1, d2, d3, d4)
}
pub fn as_u128(&self) -> u128 {
u128::from(self.as_bytes()[0]) << 120
| u128::from(self.as_bytes()[1]) << 112
| u128::from(self.as_bytes()[2]) << 104
| u128::from(self.as_bytes()[3]) << 96
| u128::from(self.as_bytes()[4]) << 88
| u128::from(self.as_bytes()[5]) << 80
| u128::from(self.as_bytes()[6]) << 72
| u128::from(self.as_bytes()[7]) << 64
| u128::from(self.as_bytes()[8]) << 56
| u128::from(self.as_bytes()[9]) << 48
| u128::from(self.as_bytes()[10]) << 40
| u128::from(self.as_bytes()[11]) << 32
| u128::from(self.as_bytes()[12]) << 24
| u128::from(self.as_bytes()[13]) << 16
| u128::from(self.as_bytes()[14]) << 8
| u128::from(self.as_bytes()[15])
}
pub fn to_u128_le(&self) -> u128 {
u128::from(self.as_bytes()[0])
| u128::from(self.as_bytes()[1]) << 8
| u128::from(self.as_bytes()[2]) << 16
| u128::from(self.as_bytes()[3]) << 24
| u128::from(self.as_bytes()[4]) << 32
| u128::from(self.as_bytes()[5]) << 40
| u128::from(self.as_bytes()[6]) << 48
| u128::from(self.as_bytes()[7]) << 56
| u128::from(self.as_bytes()[8]) << 64
| u128::from(self.as_bytes()[9]) << 72
| u128::from(self.as_bytes()[10]) << 80
| u128::from(self.as_bytes()[11]) << 88
| u128::from(self.as_bytes()[12]) << 96
| u128::from(self.as_bytes()[13]) << 104
| u128::from(self.as_bytes()[14]) << 112
| u128::from(self.as_bytes()[15]) << 120
}
pub const fn as_bytes(&self) -> &Bytes {
&self.0
}
pub fn is_nil(&self) -> bool {
self.as_bytes().iter().all(|&b| b == 0)
}
pub const fn encode_buffer() -> [u8; adapter::Urn::LENGTH] {
[0; adapter::Urn::LENGTH]
}
}
impl fmt::Debug for Uuid {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::LowerHex::fmt(self, f)
}
}
impl fmt::Display for Uuid {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::LowerHex::fmt(self, f)
}
}
impl fmt::Display for Variant {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Variant::NCS => write!(f, "NCS"),
Variant::RFC4122 => write!(f, "RFC4122"),
Variant::Microsoft => write!(f, "Microsoft"),
Variant::Future => write!(f, "Future"),
}
}
}
impl fmt::LowerHex for Uuid {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::LowerHex::fmt(&self.to_hyphenated_ref(), f)
}
}
impl fmt::UpperHex for Uuid {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::UpperHex::fmt(&self.to_hyphenated_ref(), f)
}
}
impl str::FromStr for Uuid {
type Err = Error;
fn from_str(uuid_str: &str) -> Result<Self, Self::Err> {
Uuid::parse_str(uuid_str)
}
}
impl Default for Uuid {
#[inline]
fn default() -> Self {
Uuid::nil()
}
}
#[cfg(test)]
mod tests {
use crate::{
prelude::*,
std::string::{String, ToString},
test_util,
};
macro_rules! check {
($buf:ident, $format:expr, $target:expr, $len:expr, $cond:expr) => {
$buf.clear();
write!($buf, $format, $target).unwrap();
assert!($buf.len() == $len);
assert!($buf.chars().all($cond), "{}", $buf);
};
}
#[test]
fn test_uuid_compare() {
let uuid1 = test_util::new();
let uuid2 = test_util::new2();
assert_eq!(uuid1, uuid1);
assert_eq!(uuid2, uuid2);
assert_ne!(uuid1, uuid2);
assert_ne!(uuid2, uuid1);
}
#[test]
fn test_uuid_default() {
let default_uuid = Uuid::default();
let nil_uuid = Uuid::nil();
assert_eq!(default_uuid, nil_uuid);
}
#[test]
fn test_uuid_display() {
use super::fmt::Write;
let uuid = test_util::new();
let s = uuid.to_string();
let mut buffer = String::new();
assert_eq!(s, uuid.to_hyphenated().to_string());
check!(buffer, "{}", uuid, 36, |c| c.is_lowercase()
|| c.is_digit(10)
|| c == '-');
}
#[test]
fn test_uuid_lowerhex() {
use super::fmt::Write;
let mut buffer = String::new();
let uuid = test_util::new();
check!(buffer, "{:x}", uuid, 36, |c| c.is_lowercase()
|| c.is_digit(10)
|| c == '-');
}
#[test]
fn test_uuid_operator_eq() {
let uuid1 = test_util::new();
let uuid1_dup = uuid1.clone();
let uuid2 = test_util::new2();
assert!(uuid1 == uuid1);
assert!(uuid1 == uuid1_dup);
assert!(uuid1_dup == uuid1);
assert!(uuid1 != uuid2);
assert!(uuid2 != uuid1);
assert!(uuid1_dup != uuid2);
assert!(uuid2 != uuid1_dup);
}
#[test]
fn test_uuid_to_string() {
use super::fmt::Write;
let uuid = test_util::new();
let s = uuid.to_string();
let mut buffer = String::new();
assert_eq!(s.len(), 36);
check!(buffer, "{}", s, 36, |c| c.is_lowercase()
|| c.is_digit(10)
|| c == '-');
}
#[test]
fn test_uuid_upperhex() {
use super::fmt::Write;
let mut buffer = String::new();
let uuid = test_util::new();
check!(buffer, "{:X}", uuid, 36, |c| c.is_uppercase()
|| c.is_digit(10)
|| c == '-');
}
#[test]
fn test_nil() {
let nil = Uuid::nil();
let not_nil = test_util::new();
let from_bytes = Uuid::from_bytes([
4, 54, 67, 12, 43, 2, 2, 76, 32, 50, 87, 5, 1, 33, 43, 87,
]);
assert_eq!(from_bytes.get_version(), None);
assert!(nil.is_nil());
assert!(!not_nil.is_nil());
assert_eq!(nil.get_version(), Some(Version::Nil));
assert_eq!(not_nil.get_version(), Some(Version::Random))
}
#[test]
fn test_predefined_namespaces() {
assert_eq!(
Uuid::NAMESPACE_DNS.to_hyphenated().to_string(),
"6ba7b810-9dad-11d1-80b4-00c04fd430c8"
);
assert_eq!(
Uuid::NAMESPACE_URL.to_hyphenated().to_string(),
"6ba7b811-9dad-11d1-80b4-00c04fd430c8"
);
assert_eq!(
Uuid::NAMESPACE_OID.to_hyphenated().to_string(),
"6ba7b812-9dad-11d1-80b4-00c04fd430c8"
);
assert_eq!(
Uuid::NAMESPACE_X500.to_hyphenated().to_string(),
"6ba7b814-9dad-11d1-80b4-00c04fd430c8"
);
}
#[cfg(feature = "v3")]
#[test]
fn test_get_version_v3() {
let uuid =
Uuid::new_v3(&Uuid::NAMESPACE_DNS, "rust-lang.org".as_bytes());
assert_eq!(uuid.get_version().unwrap(), Version::Md5);
assert_eq!(uuid.get_version_num(), 3);
}
#[test]
fn test_get_variant() {
let uuid1 = test_util::new();
let uuid2 =
Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap();
let uuid3 =
Uuid::parse_str("67e55044-10b1-426f-9247-bb680e5fe0c8").unwrap();
let uuid4 =
Uuid::parse_str("936DA01F9ABD4d9dC0C702AF85C822A8").unwrap();
let uuid5 =
Uuid::parse_str("F9168C5E-CEB2-4faa-D6BF-329BF39FA1E4").unwrap();
let uuid6 =
Uuid::parse_str("f81d4fae-7dec-11d0-7765-00a0c91e6bf6").unwrap();
assert_eq!(uuid1.get_variant().unwrap(), Variant::RFC4122);
assert_eq!(uuid2.get_variant().unwrap(), Variant::RFC4122);
assert_eq!(uuid3.get_variant().unwrap(), Variant::RFC4122);
assert_eq!(uuid4.get_variant().unwrap(), Variant::Microsoft);
assert_eq!(uuid5.get_variant().unwrap(), Variant::Microsoft);
assert_eq!(uuid6.get_variant().unwrap(), Variant::NCS);
}
#[test]
fn test_to_simple_string() {
let uuid1 = test_util::new();
let s = uuid1.to_simple().to_string();
assert_eq!(s.len(), 32);
assert!(s.chars().all(|c| c.is_digit(16)));
}
#[test]
fn test_to_hyphenated_string() {
let uuid1 = test_util::new();
let s = uuid1.to_hyphenated().to_string();
assert!(s.len() == 36);
assert!(s.chars().all(|c| c.is_digit(16) || c == '-'));
}
#[test]
fn test_upper_lower_hex() {
use std::fmt::Write;
let mut buf = String::new();
let u = test_util::new();
macro_rules! check {
($buf:ident, $format:expr, $target:expr, $len:expr, $cond:expr) => {
$buf.clear();
write!($buf, $format, $target).unwrap();
assert!(buf.len() == $len);
assert!($buf.chars().all($cond), "{}", $buf);
};
}
check!(buf, "{:X}", u, 36, |c| c.is_uppercase()
|| c.is_digit(10)
|| c == '-');
check!(buf, "{:X}", u.to_hyphenated(), 36, |c| c.is_uppercase()
|| c.is_digit(10)
|| c == '-');
check!(buf, "{:X}", u.to_simple(), 32, |c| c.is_uppercase()
|| c.is_digit(10));
check!(buf, "{:x}", u.to_hyphenated(), 36, |c| c.is_lowercase()
|| c.is_digit(10)
|| c == '-');
check!(buf, "{:x}", u.to_simple(), 32, |c| c.is_lowercase()
|| c.is_digit(10));
}
#[test]
fn test_to_urn_string() {
let uuid1 = test_util::new();
let ss = uuid1.to_urn().to_string();
let s = &ss[9..];
assert!(ss.starts_with("urn:uuid:"));
assert_eq!(s.len(), 36);
assert!(s.chars().all(|c| c.is_digit(16) || c == '-'));
}
#[test]
fn test_to_simple_string_matching() {
let uuid1 = test_util::new();
let hs = uuid1.to_hyphenated().to_string();
let ss = uuid1.to_simple().to_string();
let hsn = hs.chars().filter(|&c| c != '-').collect::<String>();
assert_eq!(hsn, ss);
}
#[test]
fn test_string_roundtrip() {
let uuid = test_util::new();
let hs = uuid.to_hyphenated().to_string();
let uuid_hs = Uuid::parse_str(&hs).unwrap();
assert_eq!(uuid_hs, uuid);
let ss = uuid.to_string();
let uuid_ss = Uuid::parse_str(&ss).unwrap();
assert_eq!(uuid_ss, uuid);
}
#[test]
fn test_from_fields() {
let d1: u32 = 0xa1a2a3a4;
let d2: u16 = 0xb1b2;
let d3: u16 = 0xc1c2;
let d4 = [0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8];
let u = Uuid::from_fields(d1, d2, d3, &d4).unwrap();
let expected = "a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8";
let result = u.to_simple().to_string();
assert_eq!(result, expected);
}
#[test]
fn test_from_fields_le() {
let d1: u32 = 0xa4a3a2a1;
let d2: u16 = 0xb2b1;
let d3: u16 = 0xc2c1;
let d4 = [0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8];
let u = Uuid::from_fields_le(d1, d2, d3, &d4).unwrap();
let expected = "a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8";
let result = u.to_simple().to_string();
assert_eq!(result, expected);
}
#[test]
fn test_as_fields() {
let u = test_util::new();
let (d1, d2, d3, d4) = u.as_fields();
assert_ne!(d1, 0);
assert_ne!(d2, 0);
assert_ne!(d3, 0);
assert_eq!(d4.len(), 8);
assert!(!d4.iter().all(|&b| b == 0));
}
#[test]
fn test_fields_roundtrip() {
let d1_in: u32 = 0xa1a2a3a4;
let d2_in: u16 = 0xb1b2;
let d3_in: u16 = 0xc1c2;
let d4_in = &[0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8];
let u = Uuid::from_fields(d1_in, d2_in, d3_in, d4_in).unwrap();
let (d1_out, d2_out, d3_out, d4_out) = u.as_fields();
assert_eq!(d1_in, d1_out);
assert_eq!(d2_in, d2_out);
assert_eq!(d3_in, d3_out);
assert_eq!(d4_in, d4_out);
}
#[test]
fn test_fields_le_roundtrip() {
let d1_in: u32 = 0xa4a3a2a1;
let d2_in: u16 = 0xb2b1;
let d3_in: u16 = 0xc2c1;
let d4_in = &[0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8];
let u = Uuid::from_fields_le(d1_in, d2_in, d3_in, d4_in).unwrap();
let (d1_out, d2_out, d3_out, d4_out) = u.to_fields_le();
assert_eq!(d1_in, d1_out);
assert_eq!(d2_in, d2_out);
assert_eq!(d3_in, d3_out);
assert_eq!(d4_in, d4_out);
}
#[test]
fn test_fields_le_are_actually_le() {
let d1_in: u32 = 0xa1a2a3a4;
let d2_in: u16 = 0xb1b2;
let d3_in: u16 = 0xc1c2;
let d4_in = &[0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8];
let u = Uuid::from_fields(d1_in, d2_in, d3_in, d4_in).unwrap();
let (d1_out, d2_out, d3_out, d4_out) = u.to_fields_le();
assert_eq!(d1_in, d1_out.swap_bytes());
assert_eq!(d2_in, d2_out.swap_bytes());
assert_eq!(d3_in, d3_out.swap_bytes());
assert_eq!(d4_in, d4_out);
}
#[test]
fn test_from_u128() {
let v_in: u128 = 0xa1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8;
let u = Uuid::from_u128(v_in);
let expected = "a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8";
let result = u.to_simple().to_string();
assert_eq!(result, expected);
}
#[test]
fn test_from_u128_le() {
let v_in: u128 = 0xd8d7d6d5d4d3d2d1c2c1b2b1a4a3a2a1;
let u = Uuid::from_u128_le(v_in);
let expected = "a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8";
let result = u.to_simple().to_string();
assert_eq!(result, expected);
}
#[test]
fn test_u128_roundtrip() {
let v_in: u128 = 0xa1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8;
let u = Uuid::from_u128(v_in);
let v_out = u.as_u128();
assert_eq!(v_in, v_out);
}
#[test]
fn test_u128_le_roundtrip() {
let v_in: u128 = 0xd8d7d6d5d4d3d2d1c2c1b2b1a4a3a2a1;
let u = Uuid::from_u128_le(v_in);
let v_out = u.to_u128_le();
assert_eq!(v_in, v_out);
}
#[test]
fn test_u128_le_is_actually_le() {
let v_in: u128 = 0xa1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8;
let u = Uuid::from_u128(v_in);
let v_out = u.to_u128_le();
assert_eq!(v_in, v_out.swap_bytes());
}
#[test]
fn test_from_slice() {
let b = [
0xa1, 0xa2, 0xa3, 0xa4, 0xb1, 0xb2, 0xc1, 0xc2, 0xd1, 0xd2, 0xd3,
0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
];
let u = Uuid::from_slice(&b).unwrap();
let expected = "a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8";
assert_eq!(u.to_simple().to_string(), expected);
}
#[test]
fn test_from_bytes() {
let b = [
0xa1, 0xa2, 0xa3, 0xa4, 0xb1, 0xb2, 0xc1, 0xc2, 0xd1, 0xd2, 0xd3,
0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
];
let u = Uuid::from_bytes(b);
let expected = "a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8";
assert_eq!(u.to_simple().to_string(), expected);
}
#[test]
fn test_as_bytes() {
let u = test_util::new();
let ub = u.as_bytes();
assert_eq!(ub.len(), 16);
assert!(!ub.iter().all(|&b| b == 0));
}
#[test]
fn test_bytes_roundtrip() {
let b_in: crate::Bytes = [
0xa1, 0xa2, 0xa3, 0xa4, 0xb1, 0xb2, 0xc1, 0xc2, 0xd1, 0xd2, 0xd3,
0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
];
let u = Uuid::from_slice(&b_in).unwrap();
let b_out = u.as_bytes();
assert_eq!(&b_in, b_out);
}
#[test]
fn test_iterbytes_impl_for_uuid() {
let mut set = std::collections::HashSet::new();
let id1 = test_util::new();
let id2 = test_util::new2();
set.insert(id1.clone());
assert!(set.contains(&id1));
assert!(!set.contains(&id2));
}
}