Skip to main content

uuid/
fmt.rs

1use core::fmt;
2use std::{
3    ptr,
4    string::{String, ToString},
5};
6
7use crate::{Error, Uuid};
8
9impl Default for Uuid {
10    #[inline]
11    fn default() -> Self {
12        Uuid::nil()
13    }
14}
15
16impl AsRef<Uuid> for Uuid {
17    #[inline]
18    fn as_ref(&self) -> &Uuid {
19        self
20    }
21}
22
23impl AsRef<[u8]> for Uuid {
24    #[inline]
25    fn as_ref(&self) -> &[u8] {
26        &self.0
27    }
28}
29
30impl From<Uuid> for std::vec::Vec<u8> {
31    fn from(value: Uuid) -> Self {
32        value.0.to_vec()
33    }
34}
35
36impl std::convert::TryFrom<std::vec::Vec<u8>> for Uuid {
37    type Error = Error;
38
39    fn try_from(value: std::vec::Vec<u8>) -> Result<Self, Self::Error> {
40        Uuid::from_slice(&value)
41    }
42}
43
44impl std::fmt::Debug for Uuid {
45    #[inline]
46    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
47        std::fmt::LowerHex::fmt(self, f)
48    }
49}
50
51impl std::fmt::Display for Uuid {
52    #[inline]
53    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54        std::fmt::LowerHex::fmt(self, f)
55    }
56}
57
58impl From<Uuid> for String {
59    #[inline]
60    fn from(uuid: Uuid) -> Self {
61        uuid.to_string()
62    }
63}
64
65impl std::fmt::LowerHex for Uuid {
66    #[inline]
67    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68        let mut hyphenated_buf = format_hyphenated(&self.0, false);
69        let hyphenated_str = unsafe { std::str::from_utf8_unchecked_mut(&mut hyphenated_buf) };
70
71        return f.write_str(hyphenated_str);
72    }
73}
74
75impl fmt::UpperHex for Uuid {
76    #[inline]
77    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78        let mut hyphenated_buf = format_hyphenated(&self.0, false);
79        let hyphenated_str = unsafe { std::str::from_utf8_unchecked_mut(&mut hyphenated_buf) };
80        let upper_hex = hyphenated_str.to_uppercase();
81
82        return f.write_str(&upper_hex);
83    }
84}
85
86impl Uuid {
87    pub fn encode_lower<'buf>(&self, buffer: &'buf mut [u8]) -> &'buf mut str {
88        encode_hyphenated(self.as_bytes(), buffer, false)
89    }
90
91    pub const fn encode_buffer() -> [u8; HYPHENATED_LENGTH] {
92        [0; HYPHENATED_LENGTH]
93    }
94}
95
96#[inline]
97fn encode_hyphenated<'b>(src: &[u8; 16], buffer: &'b mut [u8], upper: bool) -> &'b mut str {
98    let buf = &mut buffer[..HYPHENATED_LENGTH];
99    let dst = buf.as_mut_ptr();
100
101    // SAFETY: `buf` is guaranteed to be at least `LEN` bytes
102    // SAFETY: The encoded buffer is ASCII encoded
103    unsafe {
104        ptr::write(dst.cast(), format_hyphenated(src, upper));
105        std::str::from_utf8_unchecked_mut(buf)
106    }
107}
108
109const HYPHENATED_LENGTH: usize = 36;
110
111const UPPER: [u8; 16] = [
112    b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'A', b'B', b'C', b'D', b'E', b'F',
113];
114const LOWER: [u8; 16] = [
115    b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'a', b'b', b'c', b'd', b'e', b'f',
116];
117
118const fn format_hyphenated(src: &[u8; 16], upper: bool) -> [u8; 36] {
119    let lut = if upper { &UPPER } else { &LOWER };
120    let groups = [(0, 8), (9, 13), (14, 18), (19, 23), (24, 36)];
121    let mut dst = [0; 36];
122
123    let mut group_idx = 0;
124    let mut i = 0;
125    while group_idx < 5 {
126        let (start, end) = groups[group_idx];
127        let mut j = start;
128        while j < end {
129            let x = src[i];
130            i += 1;
131
132            dst[j] = lut[(x >> 4) as usize];
133            dst[j + 1] = lut[(x & 0x0f) as usize];
134            j += 2;
135        }
136        if group_idx < 4 {
137            dst[end] = b'-';
138        }
139        group_idx += 1;
140    }
141    dst
142}