#![doc(html_root_url = "https://docs.rs/simple-uuid")]
mod name;
mod rand;
mod time;
use core::fmt;
use core::sync::atomic;
use std::time::SystemTime;
pub const UTC_EPOCH: u64 = 0x1b21_dd21_3814_000;
#[derive(Debug, Default)]
pub struct Layout {
pub field_low: u32,
pub field_mid: u16,
pub field_high_and_version: u16,
pub clock_seq_high_and_reserved: u8,
pub clock_seq_low: u8,
pub node: Node,
}
impl Layout {
pub fn be_fields(&self) -> (u32, u16, u16, u16, Node) {
(
self.field_low.to_be(),
self.field_mid.to_be(),
self.field_high_and_version.to_be(),
((self.clock_seq_high_and_reserved as u16) << 8 | self.clock_seq_low as u16).to_be(),
self.node,
)
}
pub fn le_fields(&self) -> (u32, u16, u16, u16, Node) {
(
self.field_low.to_le(),
self.field_mid.to_le(),
self.field_high_and_version.to_le(),
((self.clock_seq_high_and_reserved as u16) << 8 | self.clock_seq_low as u16).to_le(),
self.node,
)
}
pub fn as_bytes(&self) -> UUID {
UUID([
self.field_low.to_be_bytes()[0],
self.field_low.to_be_bytes()[1],
self.field_low.to_be_bytes()[2],
self.field_low.to_be_bytes()[3],
self.field_mid.to_be_bytes()[0],
self.field_mid.to_be_bytes()[1],
self.field_high_and_version.to_be_bytes()[0],
self.field_high_and_version.to_be_bytes()[1],
self.clock_seq_high_and_reserved,
self.clock_seq_low,
self.node.0[0],
self.node.0[1],
self.node.0[2],
self.node.0[3],
self.node.0[4],
self.node.0[5],
])
}
pub fn get_version(&self) -> Option<Version> {
match (self.field_high_and_version >> 12) & 0xf {
0x01 => Some(Version::TIME),
0x02 => Some(Version::DCE),
0x03 => Some(Version::MD5),
0x04 => Some(Version::RAND),
0x05 => Some(Version::SHA1),
_ => None,
}
}
pub fn get_variant(&self) -> Option<Variant> {
match (self.clock_seq_high_and_reserved >> 4) & 0xf {
0x00 => Some(Variant::NCS),
0x01 => Some(Variant::RFC),
0x02 => Some(Variant::MS),
0x03 => Some(Variant::FUT),
_ => None,
}
}
pub fn get_time(&self) -> u64 {
self.field_low as u64
}
pub fn get_mac(&self) -> Node {
self.node
}
}
#[derive(Debug, Copy, Clone)]
pub enum Domain {
PERSON = 0,
GROUP,
ORG,
}
#[derive(Debug, Eq, PartialEq)]
pub enum Variant {
NCS = 0,
RFC,
MS,
FUT,
}
#[derive(Debug, Eq, PartialEq)]
pub enum Version {
TIME = 1,
DCE,
MD5,
RAND,
SHA1,
}
#[derive(Debug, Eq, PartialEq, Default)]
pub struct Timestamp(u64);
impl Timestamp {
pub fn new() -> u64 {
let utc = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.checked_add(std::time::Duration::from_nanos(UTC_EPOCH))
.unwrap()
.as_nanos();
(utc & 0xffff_ffff_ffff_fff) as u64
}
}
#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)]
pub struct UUID([u8; 16]);
impl UUID {
pub const NAMESPACE_DNS: UUID = UUID([
0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30,
0xc8,
]);
pub const NAMESPACE_OID: UUID = UUID([
0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30,
0xc8,
]);
pub const NAMESPACE_URL: UUID = UUID([
0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30,
0xc8,
]);
pub const NAMESPACE_X500: UUID = UUID([
0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30,
0xc8,
]);
}
impl fmt::LowerHex for UUID {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
fmt,
"{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
self.0[0],
self.0[1],
self.0[2],
self.0[3],
self.0[4],
self.0[5],
self.0[6],
self.0[7],
self.0[8],
self.0[9],
self.0[10],
self.0[11],
self.0[12],
self.0[13],
self.0[14],
self.0[15],
)
}
}
impl fmt::UpperHex for UUID {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
fmt,
"{:02X}{:02X}{:02X}{:02X}-{:02X}{:02X}-{:02X}{:02X}-{:02X}{:02X}-{:02X}{:02X}{:02X}{:02X}{:02X}{:02X}",
self.0[0],
self.0[1],
self.0[2],
self.0[3],
self.0[4],
self.0[5],
self.0[6],
self.0[7],
self.0[8],
self.0[9],
self.0[10],
self.0[11],
self.0[12],
self.0[13],
self.0[14],
self.0[15],
)
}
}
impl ToString for UUID {
fn to_string(&self) -> String {
format!(
"{:02}{:02}{:02}{:02}-{:02}{:02}-{:02}{:02}-{:02}{:02}-{:02}{:02}{:02}{:02}{:02}{:02}",
self.0[0],
self.0[1],
self.0[2],
self.0[3],
self.0[4],
self.0[5],
self.0[6],
self.0[7],
self.0[8],
self.0[9],
self.0[10],
self.0[11],
self.0[12],
self.0[13],
self.0[14],
self.0[15],
)
}
}
pub struct ClockSeq(pub u16);
impl ClockSeq {
pub fn new(r: u16) -> u16 {
atomic::AtomicU16::new(r).fetch_add(1, atomic::Ordering::SeqCst)
}
}
#[derive(Debug, PartialEq, Default, Copy, Clone)]
pub struct Node(pub [u8; 6]);
impl fmt::LowerHex for Node {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
fmt,
"{:02x}-{:02x}-{:02x}-{:02x}-{:02x}-{:02x}",
self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5],
)
}
}
impl fmt::UpperHex for Node {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
fmt,
"{:02X}-{:02X}-{:02X}-{:02X}-{:02X}-{:02X}",
self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5],
)
}
}
impl ToString for Node {
fn to_string(&self) -> String {
format!(
"{:02}-{:02}-{:02}-{:02}-{:02}-{:02}",
self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5],
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_value() {
let node = Node::default();
assert_eq!(node, Node([0; 6]));
let uuid = UUID::default();
assert_eq!(uuid, UUID([0; 16]));
let time: Timestamp = Timestamp::default();
assert_eq!(time.0.leading_zeros(), 64)
}
#[test]
fn to_string() {
let node = Node::default();
assert_eq!(node.to_string(), "00-00-00-00-00-00");
let uuid = UUID::default();
assert_eq!(uuid.to_string(), "00000000-0000-0000-0000-000000000000");
}
}