Skip to main content

pollen_types/
ids.rs

1//! Identifier types for Pollen.
2
3use serde::{Deserialize, Serialize};
4use std::fmt;
5use std::str::FromStr;
6use uuid::Uuid;
7
8/// Unique identifier for a node in the cluster.
9#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
10pub struct NodeId(pub u64);
11
12impl NodeId {
13    /// Generate a new random NodeId.
14    pub fn new() -> Self {
15        Self(rand_u64())
16    }
17
18    /// Create a NodeId from a raw u64 value.
19    pub const fn from_raw(value: u64) -> Self {
20        Self(value)
21    }
22
23    /// Get the raw u64 value.
24    pub const fn as_u64(&self) -> u64 {
25        self.0
26    }
27}
28
29impl Default for NodeId {
30    fn default() -> Self {
31        Self::new()
32    }
33}
34
35impl fmt::Debug for NodeId {
36    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37        write!(f, "NodeId({:016x})", self.0)
38    }
39}
40
41impl fmt::Display for NodeId {
42    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43        write!(f, "{:016x}", self.0)
44    }
45}
46
47impl FromStr for NodeId {
48    type Err = std::num::ParseIntError;
49
50    fn from_str(s: &str) -> Result<Self, Self::Err> {
51        u64::from_str_radix(s, 16).map(NodeId)
52    }
53}
54
55/// Unique identifier for a task definition.
56#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
57pub struct TaskId(pub Uuid);
58
59impl TaskId {
60    /// Generate a new TaskId using UUIDv7 (time-ordered).
61    pub fn new() -> Self {
62        Self(Uuid::now_v7())
63    }
64
65    /// Create a TaskId from a UUID.
66    pub const fn from_uuid(uuid: Uuid) -> Self {
67        Self(uuid)
68    }
69
70    /// Get the underlying UUID.
71    pub const fn as_uuid(&self) -> &Uuid {
72        &self.0
73    }
74
75    /// Parse a TaskId from a string.
76    pub fn parse(s: &str) -> Result<Self, uuid::Error> {
77        Ok(Self(Uuid::parse_str(s)?))
78    }
79}
80
81impl Default for TaskId {
82    fn default() -> Self {
83        Self::new()
84    }
85}
86
87impl fmt::Debug for TaskId {
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89        write!(f, "TaskId({})", self.0)
90    }
91}
92
93impl fmt::Display for TaskId {
94    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95        write!(f, "{}", self.0)
96    }
97}
98
99/// Unique identifier for a task instance (single execution).
100#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
101pub struct InstanceId(pub Uuid);
102
103impl InstanceId {
104    /// Generate a new InstanceId using UUIDv7 (time-ordered).
105    pub fn new() -> Self {
106        Self(Uuid::now_v7())
107    }
108
109    /// Create an InstanceId from a UUID.
110    pub const fn from_uuid(uuid: Uuid) -> Self {
111        Self(uuid)
112    }
113
114    /// Get the underlying UUID.
115    pub const fn as_uuid(&self) -> &Uuid {
116        &self.0
117    }
118
119    /// Parse an InstanceId from a string.
120    pub fn parse(s: &str) -> Result<Self, uuid::Error> {
121        Ok(Self(Uuid::parse_str(s)?))
122    }
123}
124
125impl Default for InstanceId {
126    fn default() -> Self {
127        Self::new()
128    }
129}
130
131impl fmt::Debug for InstanceId {
132    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133        write!(f, "InstanceId({})", self.0)
134    }
135}
136
137impl fmt::Display for InstanceId {
138    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139        write!(f, "{}", self.0)
140    }
141}
142
143/// Generate a random u64 using simple xorshift.
144fn rand_u64() -> u64 {
145    use std::time::{SystemTime, UNIX_EPOCH};
146    use std::cell::Cell;
147
148    thread_local! {
149        static STATE: Cell<u64> = Cell::new(
150            SystemTime::now()
151                .duration_since(UNIX_EPOCH)
152                .unwrap()
153                .as_nanos() as u64
154        );
155    }
156
157    STATE.with(|state| {
158        let mut x = state.get();
159        x ^= x << 13;
160        x ^= x >> 7;
161        x ^= x << 17;
162        state.set(x);
163        x
164    })
165}
166
167#[cfg(test)]
168mod tests {
169    use super::*;
170
171    #[test]
172    fn test_node_id_unique() {
173        let id1 = NodeId::new();
174        let id2 = NodeId::new();
175        assert_ne!(id1, id2);
176    }
177
178    #[test]
179    fn test_task_id_parse() {
180        let id = TaskId::new();
181        let parsed = TaskId::parse(&id.to_string()).unwrap();
182        assert_eq!(id, parsed);
183    }
184
185    #[test]
186    fn test_instance_id_ordered() {
187        let id1 = InstanceId::new();
188        std::thread::sleep(std::time::Duration::from_millis(1));
189        let id2 = InstanceId::new();
190        // UUIDv7 is time-ordered
191        assert!(id1.0 < id2.0);
192    }
193}