binary_io/
uuid.rs

1//! Support for the LCS4 uuid structure type
2//!
3
4use std::fmt::{Display, LowerHex, UpperHex};
5
6#[cfg(feature = "uuid_v1")]
7use std::time::SystemTime;
8#[cfg(feature = "uuid_v1")]
9use uuid::Uuid as V1Generator;
10
11use crate::data::{DeserializeCopy, Deserializeable, Serializeable};
12
13///
14/// A universally Unique Identifier,
15///  in a format which can be serialized according to LCS 4
16#[allow(clippy::upper_case_acronyms)]
17#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Default)]
18pub struct UUID {
19    low: u64,
20    high: u64,
21}
22
23impl UUID {
24    ///
25    /// Constructs a new UUID from the given components
26    pub const fn new(low: u64, high: u64) -> Self {
27        Self { low, high }
28    }
29
30    ///
31    /// Extracts the components of self into a tuple of (low,high)
32    pub const fn into_fields(self) -> (u64, u64) {
33        (self.low, self.high)
34    }
35
36    ///
37    /// The NIL UUID, with both components set to 0
38    pub const NIL: UUID = UUID::new(0, 0);
39
40    ///
41    /// Generates a random (v4) UUID
42    #[cfg(feature = "random_uuid")]
43    pub fn random() -> Self {
44        use rand::prelude::*;
45        let (mut high, mut low) = thread_rng().gen();
46        high = (high & !0xF000) | 0x4000;
47        low = low & !0x8000000000000000;
48        UUID { low, high }
49    }
50
51    ///
52    /// Returns a new Version 1 UUID
53    #[cfg(feature = "uuid_v1")]
54    pub fn time_based() -> Self {
55        use rand::prelude::*;
56        use uuid::v1::{Context, Timestamp};
57        static SEQ: Context = Context::new(0);
58        let bytes = thread_rng().gen::<[u8; 6]>();
59        let time = SystemTime::now()
60            .duration_since(SystemTime::UNIX_EPOCH)
61            .unwrap();
62        let ts = Timestamp::from_unix(&SEQ, time.as_secs(), time.subsec_nanos());
63        let other = V1Generator::new_v1(ts, &bytes).unwrap();
64        let fields = other.as_fields();
65        let high = ((fields.0 as u64) << 32) | ((fields.1 as u64) << 16) | (fields.2 as u64);
66        let low = u64::from_be_bytes(*fields.3);
67        UUID { high, low }
68    }
69}
70
71impl From<u128> for UUID {
72    fn from(v: u128) -> Self {
73        Self::new(v as u64, (v >> 64) as u64)
74    }
75}
76
77impl From<UUID> for u128 {
78    fn from(u: UUID) -> Self {
79        ((u.high as u128) << 64) | (u.low as u128)
80    }
81}
82
83impl Display for UUID {
84    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85        let h0 = (self.high >> 32) as u32;
86        let h1 = (self.high & 0xffff0000 >> 16) as u16;
87        let h2 = (self.high & 0xffff) as u16;
88        let l0 = (self.low >> 48) as u16;
89        let l1 = self.low & 0xffffffffffff;
90        f.write_fmt(format_args!(
91            "{:08x}-{:08x}-{:08x}-{:08x}-{:08x}",
92            h0, h1, h2, l0, l1
93        ))
94    }
95}
96
97// Just do the same thing as display, that's the default
98impl LowerHex for UUID {
99    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100        let h0 = (self.high >> 32) as u32;
101        let h1 = (self.high & 0xffff0000 >> 16) as u16;
102        let h2 = (self.high & 0xffff) as u16;
103        let l0 = (self.low >> 48) as u16;
104        let l1 = self.low & 0xffffffffffff;
105        f.write_fmt(format_args!(
106            "{:08x}-{:08x}-{:08x}-{:08x}-{:08x}",
107            h0, h1, h2, l0, l1
108        ))
109    }
110}
111
112// Use `{:X}` for the format of the inner fields
113impl UpperHex for UUID {
114    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
115        let h0 = (self.high >> 32) as u32;
116        let h1 = (self.high & 0xffff0000 >> 16) as u16;
117        let h2 = (self.high & 0xffff) as u16;
118        let l0 = (self.low >> 48) as u16;
119        let l1 = self.low & 0xffffffffffff;
120        f.write_fmt(format_args!(
121            "{:08X}-{:08X}-{:08X}-{:08X}-{:08X}",
122            h0, h1, h2, l0, l1
123        ))
124    }
125}
126
127impl Serializeable for UUID {
128    fn serialize<W: crate::data::DataOutput + ?Sized>(
129        &self,
130        output: &mut W,
131    ) -> std::io::Result<()> {
132        self.high.serialize(output)?;
133        self.low.serialize(output)
134    }
135}
136
137impl Deserializeable for UUID {
138    fn deserialize<R: crate::data::DataInput + ?Sized>(
139        &mut self,
140        input: &mut R,
141    ) -> std::io::Result<()> {
142        self.high.deserialize(input)?;
143        self.low.deserialize(input)
144    }
145}
146
147impl DeserializeCopy for UUID {
148    fn deserialize_copy<R: crate::data::DataInput + ?Sized>(
149        input: &mut R,
150    ) -> std::io::Result<Self> {
151        Ok(Self {
152            high: u64::deserialize_copy(input)?,
153            low: u64::deserialize_copy(input)?,
154        })
155    }
156}