Skip to main content

kcl_lib/execution/
id_generator.rs

1//! A generator for ArtifactIds that can be stable across executions.
2
3use crate::execution::ArtifactId;
4use crate::execution::ModuleId;
5
6const NAMESPACE_KCL: uuid::Uuid = uuid::uuid!("8bda3118-75eb-58c7-a866-bef1dcb495e7");
7
8/// A generator for ArtifactIds that can be stable across executions.
9#[derive(Debug, Clone, Default, PartialEq)]
10pub struct IdGenerator {
11    module_id: Option<ModuleId>,
12    next_id: u64,
13    namespace: Option<uuid::Uuid>,
14}
15
16impl IdGenerator {
17    pub fn new(module_id: Option<ModuleId>) -> Self {
18        Self {
19            module_id,
20            next_id: 0,
21            namespace: None,
22        }
23    }
24
25    /// A stable client namespace makes follow-up command IDs repeatable without
26    /// reusing IDs allocated by the remote interpreter.
27    #[cfg(not(target_arch = "wasm32"))]
28    pub(super) fn remote_session() -> Self {
29        Self {
30            namespace: Some(uuid::Uuid::new_v5(&NAMESPACE_KCL, b"remote-client")),
31            ..Self::default()
32        }
33    }
34
35    pub fn next_uuid(&mut self) -> uuid::Uuid {
36        let next_id = self.next_id;
37
38        let next = format!(
39            "{} {}",
40            self.module_id.map(|id| id.to_string()).unwrap_or("none".to_string()),
41            next_id
42        );
43        let next_uuid = uuid::Uuid::new_v5(self.namespace.as_ref().unwrap_or(&NAMESPACE_KCL), next.as_bytes());
44
45        self.next_id += 1;
46
47        next_uuid
48    }
49
50    pub fn next_artifact_id(&mut self) -> ArtifactId {
51        ArtifactId::new(self.next_uuid())
52    }
53}
54
55#[cfg(test)]
56mod tests {
57    use super::*;
58
59    #[test]
60    fn test_id_generator() {
61        let mut generator = IdGenerator::new(Some(ModuleId::default()));
62
63        let uuid1 = generator.next_uuid();
64        let uuid2 = generator.next_uuid();
65
66        assert_ne!(uuid1, uuid2);
67    }
68
69    #[test]
70    // Test that the same generator produces the same UUIDs.
71    fn test_id_generator_stable() {
72        let mut generator = IdGenerator::new(Some(ModuleId::default()));
73
74        let uuid1 = generator.next_uuid();
75        let uuid2 = generator.next_uuid();
76
77        let mut generator = IdGenerator::new(Some(ModuleId::default()));
78
79        let uuid3 = generator.next_uuid();
80        let uuid4 = generator.next_uuid();
81
82        assert_eq!(uuid1, uuid3);
83        assert_eq!(uuid2, uuid4);
84    }
85
86    #[test]
87    // Generate 20 uuids and make sure all are unique.
88    fn test_id_generator_unique() {
89        let mut generator = IdGenerator::new(Some(ModuleId::default()));
90
91        let mut uuids = Vec::new();
92
93        for _ in 0..20 {
94            uuids.push(generator.next_uuid());
95        }
96
97        for i in 0..uuids.len() {
98            for j in i + 1..uuids.len() {
99                assert_ne!(uuids[i], uuids[j]);
100            }
101        }
102    }
103}