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