Skip to main content

kojin_core/
task_id.rs

1use serde::{Deserialize, Serialize};
2use std::fmt;
3use uuid::Uuid;
4
5/// Unique task identifier backed by UUID v7 (time-ordered).
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
7#[serde(transparent)]
8pub struct TaskId(Uuid);
9
10impl TaskId {
11    /// Create a new time-ordered task ID.
12    pub fn new() -> Self {
13        Self(Uuid::now_v7())
14    }
15
16    /// Create from an existing UUID.
17    pub fn from_uuid(uuid: Uuid) -> Self {
18        Self(uuid)
19    }
20
21    /// Get the inner UUID.
22    pub fn as_uuid(&self) -> &Uuid {
23        &self.0
24    }
25}
26
27impl Default for TaskId {
28    fn default() -> Self {
29        Self::new()
30    }
31}
32
33impl fmt::Display for TaskId {
34    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35        self.0.fmt(f)
36    }
37}
38
39impl From<Uuid> for TaskId {
40    fn from(uuid: Uuid) -> Self {
41        Self(uuid)
42    }
43}
44
45impl From<TaskId> for Uuid {
46    fn from(id: TaskId) -> Self {
47        id.0
48    }
49}
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54
55    #[test]
56    fn task_id_ordering() {
57        let id1 = TaskId::new();
58        let id2 = TaskId::new();
59        assert!(id1 < id2, "UUID v7 should be time-ordered");
60    }
61
62    #[test]
63    fn task_id_display() {
64        let id = TaskId::new();
65        let s = id.to_string();
66        assert!(!s.is_empty());
67        // UUID format: 8-4-4-4-12
68        assert_eq!(s.len(), 36);
69    }
70
71    #[test]
72    fn task_id_serde_roundtrip() {
73        let id = TaskId::new();
74        let json = serde_json::to_string(&id).unwrap();
75        let deserialized: TaskId = serde_json::from_str(&json).unwrap();
76        assert_eq!(id, deserialized);
77    }
78}