Skip to main content

selium_kernel/drivers/
singleton.rs

1//! Hostcall drivers for singleton dependency registration and lookup.
2
3use std::{
4    future::{Future, ready},
5    sync::Arc,
6};
7
8use wasmtime::Caller;
9
10use crate::{
11    guest_data::{GuestError, GuestResult},
12    operation::{Contract, Operation},
13    registry::InstanceRegistry,
14};
15use selium_abi::{GuestResourceId, SingletonLookup, SingletonRegister};
16
17type SingletonOps = (
18    Arc<Operation<SingletonRegisterDriver>>,
19    Arc<Operation<SingletonLookupDriver>>,
20);
21
22/// Hostcall driver that registers singleton dependencies.
23pub struct SingletonRegisterDriver;
24/// Hostcall driver that looks up singleton dependencies.
25pub struct SingletonLookupDriver;
26
27impl Contract for SingletonRegisterDriver {
28    type Input = SingletonRegister;
29    type Output = ();
30
31    fn to_future(
32        &self,
33        caller: &mut Caller<'_, InstanceRegistry>,
34        input: Self::Input,
35    ) -> impl Future<Output = GuestResult<Self::Output>> + 'static {
36        let registry = caller.data().registry_arc();
37        let SingletonRegister { id, resource } = input;
38
39        ready((|| -> GuestResult<Self::Output> {
40            let resource_id = registry
41                .resolve_shared(resource)
42                .ok_or(GuestError::NotFound)?;
43            registry.metadata(resource_id).ok_or(GuestError::NotFound)?;
44            let inserted = registry.register_singleton(id, resource_id)?;
45            if !inserted {
46                return Err(GuestError::StableIdExists);
47            }
48            Ok(())
49        })())
50    }
51}
52
53impl Contract for SingletonLookupDriver {
54    type Input = SingletonLookup;
55    type Output = GuestResourceId;
56
57    fn to_future(
58        &self,
59        caller: &mut Caller<'_, InstanceRegistry>,
60        input: Self::Input,
61    ) -> impl Future<Output = GuestResult<Self::Output>> + 'static {
62        let registry = caller.data().registry_arc();
63        let SingletonLookup { id } = input;
64
65        ready((|| -> GuestResult<Self::Output> {
66            let resource_id = registry.singleton(id).ok_or(GuestError::NotFound)?;
67            registry.metadata(resource_id).ok_or(GuestError::NotFound)?;
68            registry.share_handle(resource_id).map_err(GuestError::from)
69        })())
70    }
71}
72
73/// Build hostcall operations for singleton registration and lookup.
74pub fn operations() -> SingletonOps {
75    (
76        Operation::from_hostcall(
77            SingletonRegisterDriver,
78            selium_abi::hostcall_contract!(SINGLETON_REGISTER),
79        ),
80        Operation::from_hostcall(
81            SingletonLookupDriver,
82            selium_abi::hostcall_contract!(SINGLETON_LOOKUP),
83        ),
84    )
85}