Skip to main content

crux_core/bridge/
registry.rs

1use std::sync::Mutex;
2
3use facet::Facet;
4use serde::{Deserialize, Serialize};
5use slab::Slab;
6
7use super::{BridgeError, FfiFormat, Request};
8use crate::bridge::request_serde::ResolveSerialized;
9use crate::{EffectFFI, ResolveError};
10
11#[allow(clippy::unsafe_derive_deserialize)]
12#[derive(Facet, Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
13#[serde(transparent)]
14#[facet(transparent)]
15pub struct EffectId(pub u32);
16
17pub struct ResolveRegistry<T: FfiFormat>(Mutex<Slab<ResolveSerialized<T>>>);
18
19impl<T: FfiFormat> Default for ResolveRegistry<T> {
20    fn default() -> Self {
21        Self(Mutex::new(Slab::with_capacity(1024)))
22    }
23}
24
25impl<T: FfiFormat> ResolveRegistry<T> {
26    /// Register an effect for future continuation, when it has been processed
27    /// and output given back to the core.
28    ///
29    /// The `effect` will be serialized into its FFI counterpart before being stored
30    /// and wrapped in a [`Request`].
31    ///
32    /// # Panics
33    ///
34    /// Panics if the internal mutex has been poisoned, or if we've run out of
35    /// available effect IDs
36    // used in docs/internals/bridge.md
37    // ANCHOR: register
38    pub fn register<Eff>(&self, effect: Eff) -> Request<Eff::Ffi>
39    where
40        Eff: EffectFFI,
41    {
42        let (effect, resolve) = effect.serialize();
43
44        let id = self
45            .0
46            .lock()
47            .expect("Registry Mutex poisoned.")
48            .insert(resolve);
49
50        Request {
51            id: EffectId(id.try_into().expect("EffectId overflow")),
52            effect,
53        }
54    }
55    // ANCHOR_END: register
56
57    /// Resume a previously registered effect. This may fail, either because `EffectId` wasn't
58    /// found or because this effect was not expected to be resumed again.
59    ///
60    /// # Errors
61    ///
62    /// Returns `BridgeError` if the stored request could not be resolved.
63    ///
64    /// # Panics
65    ///
66    /// Panics if the internal mutex has been poisoned
67    pub fn resume(&self, id: EffectId, response: &[u8]) -> Result<(), BridgeError<T>> {
68        let mut registry_lock = self.0.lock().expect("Registry Mutex poisoned");
69
70        let entry = registry_lock.get_mut(id.0 as usize);
71
72        let Some(entry) = entry else {
73            return Err(BridgeError::ProcessResponse(ResolveError::NotFound(
74                id.0.into(),
75            )));
76        };
77
78        let resolved = entry.resolve(response);
79
80        if matches!(entry, ResolveSerialized::Never) {
81            registry_lock.remove(id.0 as usize);
82        }
83
84        resolved
85    }
86}