1use std::str::FromStr;
2
3use anyhow::{Error, Result};
4use dcbor::prelude::*;
5
6use crate::tags;
7
8#[derive(Clone, Copy, Debug, Eq, PartialEq)]
27pub struct UUID([u8; Self::UUID_SIZE]);
28
29impl UUID {
30 pub const UUID_SIZE: usize = 16;
31
32 pub fn new() -> Self {
34 let mut uuid = [0u8; Self::UUID_SIZE];
35 bc_rand::fill_random_data(&mut uuid);
36 uuid[6] = (uuid[6] & 0x0f) | 0x40; uuid[8] = (uuid[8] & 0x3f) | 0x80; Self(uuid)
39 }
40
41 pub fn from_data(data: [u8; Self::UUID_SIZE]) -> Self { Self(data) }
43
44 pub fn from_data_ref(data: impl AsRef<[u8]>) -> Option<Self> {
46 let data = data.as_ref();
47 if data.len() != Self::UUID_SIZE {
48 return None;
49 }
50 let mut arr = [0u8; Self::UUID_SIZE];
51 arr.copy_from_slice(data);
52 Some(Self::from_data(arr))
53 }
54
55 pub fn data(&self) -> &[u8; Self::UUID_SIZE] { self.into() }
57
58 pub fn as_bytes(&self) -> &[u8] { self.as_ref() }
60}
61
62impl Default for UUID {
64 fn default() -> Self { Self::new() }
65}
66
67impl<'a> From<&'a UUID> for &'a [u8; UUID::UUID_SIZE] {
69 fn from(value: &'a UUID) -> Self { &value.0 }
70}
71
72impl AsRef<[u8]> for UUID {
74 fn as_ref(&self) -> &[u8] { &self.0 }
75}
76
77impl CBORTagged for UUID {
79 fn cbor_tags() -> Vec<Tag> { tags_for_values(&[tags::TAG_UUID]) }
80}
81
82impl From<UUID> for CBOR {
84 fn from(value: UUID) -> Self { value.tagged_cbor() }
85}
86
87impl CBORTaggedEncodable for UUID {
89 fn untagged_cbor(&self) -> CBOR { CBOR::to_byte_string(self.0) }
90}
91
92impl TryFrom<CBOR> for UUID {
94 type Error = dcbor::Error;
95
96 fn try_from(cbor: CBOR) -> dcbor::Result<Self> {
97 Self::from_tagged_cbor(cbor)
98 }
99}
100
101impl CBORTaggedDecodable for UUID {
103 fn from_untagged_cbor(cbor: CBOR) -> dcbor::Result<Self> {
104 let bytes = CBOR::try_into_byte_string(cbor)?;
105 if bytes.len() != Self::UUID_SIZE {
106 return Err("invalid UUID size".into());
107 }
108 let mut uuid = [0u8; Self::UUID_SIZE];
109 uuid.copy_from_slice(&bytes);
110 Ok(Self::from_data(uuid))
111 }
112}
113
114impl std::fmt::Display for UUID {
116 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
117 write!(f, "{}", String::from(self))
118 }
119}
120
121impl From<UUID> for String {
124 fn from(uuid: UUID) -> Self {
125 let hex = hex::encode(uuid.0);
126 format!(
127 "{}-{}-{}-{}-{}",
128 &hex[0..8],
129 &hex[8..12],
130 &hex[12..16],
131 &hex[16..20],
132 &hex[20..32]
133 )
134 }
135}
136
137impl From<&UUID> for String {
139 fn from(uuid: &UUID) -> Self { String::from(*uuid) }
140}
141
142impl FromStr for UUID {
144 type Err = Error;
145
146 fn from_str(s: &str) -> Result<Self, Self::Err> {
147 let s = s.trim();
148 let s = s.replace('-', "");
149 let bytes = hex::decode(s).unwrap();
150 let mut uuid = [0u8; Self::UUID_SIZE];
151 uuid.copy_from_slice(&bytes);
152 Ok(Self::from_data(uuid))
153 }
154}