Skip to main content

worker/
rpc_instance.rs

1use std::collections::HashMap;
2use std::sync::atomic::{AtomicU64, Ordering};
3use std::sync::Mutex;
4
5use serde::{Deserialize, Serialize};
6use wasm_bindgen::JsValue;
7
8#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
9pub struct RpcInstanceHandle {
10    pub id: String,
11}
12
13impl RpcInstanceHandle {
14    pub fn new(id: impl Into<String>) -> Self {
15        Self { id: id.into() }
16    }
17}
18
19#[derive(Debug, Default)]
20pub struct RpcInstanceRegistry {
21    next_id: AtomicU64,
22    instances: Mutex<HashMap<String, JsValue>>,
23}
24
25impl RpcInstanceRegistry {
26    pub fn new() -> Self {
27        Self::default()
28    }
29
30    pub fn register(&self, instance: JsValue) -> RpcInstanceHandle {
31        let id = format!("rpc-instance-{}", self.next_id.fetch_add(1, Ordering::Relaxed));
32        self.instances
33            .lock()
34            .expect("lock instance registry")
35            .insert(id.clone(), instance);
36        RpcInstanceHandle { id }
37    }
38
39    pub fn get(&self, handle: &RpcInstanceHandle) -> Option<JsValue> {
40        self.instances
41            .lock()
42            .expect("lock instance registry")
43            .get(&handle.id)
44            .cloned()
45    }
46
47    pub fn release(&self, handle: &RpcInstanceHandle) -> bool {
48        self.instances
49            .lock()
50            .expect("lock instance registry")
51            .remove(&handle.id)
52            .is_some()
53    }
54}
55
56#[cfg(all(test, target_arch = "wasm32"))]
57mod tests {
58    use super::*;
59
60    #[test]
61    fn register_get_release_cycle() {
62        let registry = RpcInstanceRegistry::new();
63        let instance = JsValue::UNDEFINED;
64
65        let handle = registry.register(instance.clone());
66        let fetched = registry.get(&handle).expect("instance exists");
67        assert!(fetched.is_undefined());
68
69        assert!(registry.release(&handle));
70        assert!(registry.get(&handle).is_none());
71    }
72
73    #[test]
74    fn double_release_returns_false_second_time() {
75        let registry = RpcInstanceRegistry::new();
76        let handle = registry.register(JsValue::UNDEFINED);
77
78        assert!(registry.release(&handle));
79        assert!(!registry.release(&handle));
80    }
81}