reifydb_type/value/identity/
mod.rs1use std::{fmt, ops::Deref, str::FromStr};
5
6use reifydb_runtime::context::{clock::Clock, rng::Rng};
7use serde::{Deserialize, Deserializer, Serialize, Serializer, de, de::Visitor};
8use uuid::Uuid;
9
10use crate::value::uuid::Uuid7;
11
12#[repr(transparent)]
14#[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Ord, Eq, Hash, Default)]
15pub struct IdentityId(pub Uuid7);
16
17impl IdentityId {
18 pub fn generate(clock: &Clock, rng: &Rng) -> Self {
20 IdentityId(Uuid7::generate(clock, rng))
21 }
22
23 pub fn new(id: Uuid7) -> Self {
25 IdentityId(id)
26 }
27
28 pub fn value(&self) -> Uuid7 {
30 self.0
31 }
32
33 pub fn anonymous() -> Self {
36 let bytes = [
37 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
38 ];
39 IdentityId(Uuid7(Uuid::from_bytes(bytes)))
40 }
41
42 pub fn root() -> Self {
45 let bytes = [
46 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
47 ];
48 IdentityId(Uuid7(Uuid::from_bytes(bytes)))
49 }
50
51 pub fn system() -> Self {
54 let bytes = [
55 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
56 ];
57 IdentityId(Uuid7(Uuid::from_bytes(bytes)))
58 }
59
60 pub fn is_anonymous(&self) -> bool {
61 *self == Self::anonymous()
62 }
63
64 pub fn is_root(&self) -> bool {
65 *self == Self::root()
66 }
67
68 pub fn is_system(&self) -> bool {
69 *self == Self::system()
70 }
71
72 pub fn is_privileged(&self) -> bool {
74 self.is_root() || self.is_system()
75 }
76}
77
78impl Deref for IdentityId {
79 type Target = Uuid7;
80
81 fn deref(&self) -> &Self::Target {
82 &self.0
83 }
84}
85
86impl PartialEq<Uuid7> for IdentityId {
87 fn eq(&self, other: &Uuid7) -> bool {
88 self.0.eq(other)
89 }
90}
91
92impl From<Uuid7> for IdentityId {
93 fn from(id: Uuid7) -> Self {
94 IdentityId(id)
95 }
96}
97
98impl From<IdentityId> for Uuid7 {
99 fn from(identity_id: IdentityId) -> Self {
100 identity_id.0
101 }
102}
103
104impl fmt::Display for IdentityId {
105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 write!(f, "{}", self.0)
107 }
108}
109
110impl Serialize for IdentityId {
111 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
112 where
113 S: Serializer,
114 {
115 self.0.serialize(serializer)
116 }
117}
118
119impl<'de> Deserialize<'de> for IdentityId {
120 fn deserialize<D>(deserializer: D) -> Result<IdentityId, D::Error>
121 where
122 D: Deserializer<'de>,
123 {
124 struct Uuid7Visitor;
125
126 impl<'de> Visitor<'de> for Uuid7Visitor {
127 type Value = IdentityId;
128
129 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
130 formatter.write_str("a UUID version 7")
131 }
132
133 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
134 where
135 E: de::Error,
136 {
137 let uuid =
138 Uuid::from_str(value).map_err(|e| E::custom(format!("invalid UUID: {}", e)))?;
139
140 if uuid.get_version_num() != 7 {
141 return Err(E::custom(format!(
142 "expected UUID v7, got v{}",
143 uuid.get_version_num()
144 )));
145 }
146
147 Ok(IdentityId(Uuid7::from(uuid)))
148 }
149
150 fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
151 where
152 E: de::Error,
153 {
154 let uuid = Uuid::from_slice(value)
155 .map_err(|e| E::custom(format!("invalid UUID bytes: {}", e)))?;
156
157 if uuid.get_version_num() != 7 {
159 return Err(E::custom(format!(
160 "expected UUID v7, got v{}",
161 uuid.get_version_num()
162 )));
163 }
164
165 Ok(IdentityId(Uuid7::from(uuid)))
166 }
167 }
168
169 if deserializer.is_human_readable() {
170 deserializer.deserialize_str(Uuid7Visitor)
171 } else {
172 deserializer.deserialize_bytes(Uuid7Visitor)
173 }
174 }
175}
176
177#[cfg(test)]
178pub mod tests {
179 use postcard::{from_bytes, to_allocvec};
180 use reifydb_runtime::context::clock::MockClock;
181 use serde_json::{from_str, to_string};
182
183 use super::*;
184
185 fn test_clock_and_rng() -> (MockClock, Clock, Rng) {
186 let mock = MockClock::from_millis(1000);
187 let clock = Clock::Mock(mock.clone());
188 let rng = Rng::seeded(42);
189 (mock, clock, rng)
190 }
191
192 #[test]
193 fn test_identity_id_creation() {
194 let (_, clock, rng) = test_clock_and_rng();
195 let id = IdentityId::generate(&clock, &rng);
196 assert_ne!(id, IdentityId::default());
197 }
198
199 #[test]
200 fn test_identity_id_from_uuid7() {
201 let (_, clock, rng) = test_clock_and_rng();
202 let uuid = Uuid7::generate(&clock, &rng);
203 let id = IdentityId::from(uuid);
204 assert_eq!(id.value(), uuid);
205 }
206
207 #[test]
208 fn test_identity_id_display() {
209 let (_, clock, rng) = test_clock_and_rng();
210 let id = IdentityId::generate(&clock, &rng);
211 let display = format!("{}", id);
212 assert!(!display.is_empty());
213 }
214
215 #[test]
216 fn test_identity_id_equality() {
217 let (_, clock, rng) = test_clock_and_rng();
218 let uuid = Uuid7::generate(&clock, &rng);
219 let id1 = IdentityId::from(uuid);
220 let id2 = IdentityId::from(uuid);
221 assert_eq!(id1, id2);
222 }
223
224 #[test]
225 fn test_identity_id_postcard_roundtrip() {
226 let (_, clock, rng) = test_clock_and_rng();
227 let id = IdentityId::generate(&clock, &rng);
228 let bytes = to_allocvec(&id).expect("postcard serialize");
229 let decoded: IdentityId = from_bytes(&bytes).expect("postcard deserialize");
230 assert_eq!(id, decoded);
231 }
232
233 #[test]
234 fn test_identity_id_postcard_roundtrip_root() {
235 let id = IdentityId::root();
236 let bytes = to_allocvec(&id).expect("postcard serialize root");
237 let decoded: IdentityId = from_bytes(&bytes).expect("postcard deserialize root");
238 assert_eq!(id, decoded);
239 }
240
241 #[test]
242 fn test_identity_id_json_roundtrip() {
243 let (_, clock, rng) = test_clock_and_rng();
244 let id = IdentityId::generate(&clock, &rng);
245 let s = to_string(&id).expect("json serialize");
246 let decoded: IdentityId = from_str(&s).expect("json deserialize");
247 assert_eq!(id, decoded);
248 }
249}