1use std::sync::Arc;
4
5use serde::{Deserialize, Serialize};
6use uuid::Uuid;
7
8#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
10#[serde(transparent)]
11pub struct StoreId(
12 pub Uuid,
14);
15
16impl std::fmt::Display for StoreId {
17 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18 self.0.fmt(f)
19 }
20}
21
22#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
24#[serde(transparent)]
25pub struct CircleId(
26 pub Uuid,
28);
29
30impl std::fmt::Display for CircleId {
31 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32 self.0.fmt(f)
33 }
34}
35
36#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
38#[serde(transparent)]
39pub struct KeyId(
40 pub Uuid,
42);
43
44impl std::fmt::Display for KeyId {
45 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46 self.0.fmt(f)
47 }
48}
49
50#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
54#[serde(transparent)]
55pub struct MemberId(
56 pub Uuid,
58);
59
60impl std::fmt::Display for MemberId {
61 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62 self.0.fmt(f)
63 }
64}
65
66impl std::str::FromStr for MemberId {
67 type Err = InvalidMemberId;
68 fn from_str(value: &str) -> Result<Self, Self::Err> {
71 canonical_uuid(value).map(Self).map_err(|_not_canonical| InvalidMemberId)
72 }
73}
74
75#[derive(Clone, Copy, Debug, PartialEq, Eq)]
77pub struct InvalidMemberId;
78
79impl std::fmt::Display for InvalidMemberId {
80 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
81 f.write_str("not a canonical member id")
82 }
83}
84
85impl std::error::Error for InvalidMemberId {}
86
87pub fn canonical_uuid(text: &str) -> Result<Uuid, NotCanonicalUuid> {
90 match Uuid::try_parse(text) {
91 Ok(id) if id.hyphenated().to_string() == text => Ok(id),
92 _ => Err(NotCanonicalUuid),
93 }
94}
95
96#[derive(Clone, Copy, Debug, PartialEq, Eq, thiserror::Error)]
98#[error("not a canonical lowercase hyphenated UUID")]
99pub struct NotCanonicalUuid;
100
101#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
103#[serde(transparent)]
104pub struct InviteId(
105 pub Uuid,
107);
108
109impl std::fmt::Display for InviteId {
110 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111 self.0.fmt(f)
112 }
113}
114
115#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
118#[serde(transparent)]
119pub struct FileId(
120 pub Uuid,
122);
123
124impl std::fmt::Display for FileId {
125 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
126 self.0.fmt(f)
127 }
128}
129
130#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
133#[serde(transparent)]
134pub struct ObjectId(
135 pub Uuid,
137);
138
139impl std::fmt::Display for ObjectId {
140 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
141 self.0.fmt(f)
142 }
143}
144
145#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
147#[serde(transparent)]
148pub struct DeviceId(
149 pub u64,
151);
152
153pub trait IdSource: Send + Sync {
155 fn new_id(&self) -> Uuid;
157
158 fn new_device_id(&self) -> DeviceId {
165 let (high, low) = self.new_id().as_u64_pair();
166 DeviceId((low & 0x3fff_ffff_ffff_ffff) | ((high & 3) << 62))
167 }
168}
169
170pub type IdSourceRef = Arc<dyn IdSource>;
172
173pub struct UuidIds;
175
176impl IdSource for UuidIds {
177 fn new_id(&self) -> Uuid {
178 Uuid::new_v4()
179 }
180}
181
182#[cfg(feature = "test-utils")]
187pub struct SequentialIds(std::sync::atomic::AtomicU64);
188
189#[cfg(feature = "test-utils")]
190impl SequentialIds {
191 pub fn new() -> Self {
193 Self(std::sync::atomic::AtomicU64::new(1))
194 }
195}
196
197#[cfg(feature = "test-utils")]
198impl IdSource for SequentialIds {
199 fn new_id(&self) -> Uuid {
200 use std::sync::atomic::Ordering;
201 let n = self
202 .0
203 .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |n| n.checked_add(1))
204 .expect("sequential id source exhausted");
205 Uuid::from_u64_pair(0x7000 | (n >> 62), 0x8000_0000_0000_0000 | (n & 0x3fff_ffff_ffff_ffff))
207 }
208}
209
210#[cfg(test)]
211#[path = "id_source_tests.rs"]
212mod tests;