wasmcloud_provider_core/
capabilities.rs

1//! # Common types used for managing native capability providers
2
3use std::error::Error;
4
5use std::any::Any;
6
7/// The dispatcher is used by a native capability provider to send commands to an actor, expecting
8/// a result containing a byte array in return
9pub trait Dispatcher: Any + Send + Sync {
10    fn dispatch(
11        &self,
12        actor: &str,
13        op: &str,
14        msg: &[u8],
15    ) -> Result<Vec<u8>, Box<dyn Error + Sync + Send>>;
16}
17
18/// The NullDispatcher is as its name implies--a dispatcher that does nothing. This is convenient for
19/// initializing a capability provider with a null dispatcher, and then swapping it for a real dispatcher
20/// when the host runtime provides one configured with the appropriate channels
21#[derive(Default)]
22pub struct NullDispatcher {}
23
24impl NullDispatcher {
25    pub fn new() -> NullDispatcher {
26        NullDispatcher {}
27    }
28}
29
30impl Dispatcher for NullDispatcher {
31    fn dispatch(
32        &self,
33        _actor: &str,
34        _op: &str,
35        _msg: &[u8],
36    ) -> Result<Vec<u8>, Box<dyn Error + Send + Sync>> {
37        unimplemented!()
38    }
39}
40
41/// Every native capability provider must implement this trait. Both portable and native capability providers
42/// must respond to the following operations: `OP_BIND_ACTOR`, `OP_REMOVE_ACTOR`
43pub trait CapabilityProvider: CloneProvider + Send + Sync {
44    /// This function will be called on the provider when the host runtime is ready and has configured a dispatcher. This function is only ever
45    /// called _once_ for a capability provider, regardless of the number of actors being managed in the host
46    fn configure_dispatch(
47        &self,
48        dispatcher: Box<dyn Dispatcher>,
49    ) -> Result<(), Box<dyn Error + Send + Sync>>;
50    /// Invoked when an actor has requested that a provider perform a given operation
51    fn handle_call(
52        &self,
53        actor: &str,
54        op: &str,
55        msg: &[u8],
56    ) -> Result<Vec<u8>, Box<dyn Error + Send + Sync>>;
57    /// This function is called to let the capability provider know that it is being removed
58    /// from the host runtime. This gives the provider an opportunity to clean up any
59    /// resources and stop any running threads.
60    /// WARNING: do not do anything in this function that can
61    /// cause a panic, including attempting to write to STDOUT while the host process is terminating
62    fn stop(&self);
63}
64
65#[doc(hidden)]
66pub trait CloneProvider {
67    fn clone_provider(&self) -> Box<dyn CapabilityProvider>;
68}
69
70impl<T> CloneProvider for T
71where
72    T: CapabilityProvider + Clone + 'static,
73{
74    fn clone_provider(&self) -> Box<dyn CapabilityProvider> {
75        Box::new(self.clone())
76    }
77}
78
79impl Clone for Box<dyn CapabilityProvider> {
80    fn clone(&self) -> Self {
81        self.clone_provider()
82    }
83}
84
85/// Wraps a constructor inside an FFI function to allow the `CapabilityProvider` trait implementation
86/// to be instantiated and used by the host runtime
87#[macro_export]
88macro_rules! capability_provider {
89    ($provider_type:ty, $constructor:path) => {
90        #[no_mangle]
91        pub extern "C" fn __capability_provider_create(
92        ) -> *mut $crate::capabilities::CapabilityProvider {
93            let constructor: fn() -> $provider_type = $constructor;
94            let object = constructor();
95            let boxed: Box<$crate::capabilities::CapabilityProvider> = Box::new(object);
96            Box::into_raw(boxed)
97        }
98    };
99}