Skip to main content

omnia_wasi_keyvalue/
host.rs

1//! # WASI Key-Value Service
2
3mod atomics_impl;
4mod batch_impl;
5mod default_impl;
6mod resource;
7mod store_impl;
8
9mod generated {
10    pub use self::wasi::keyvalue::store::Error;
11    pub use super::{BucketProxy, Cas};
12
13    wasmtime::component::bindgen!({
14        world: "imports",
15        path: "wit",
16        imports: {
17            default: store | tracing | trappable,
18        },
19        with: {
20            "wasi:keyvalue/store.bucket": BucketProxy,
21            "wasi:keyvalue/atomics.cas": Cas,
22        },
23        trappable_error_type: {
24            "wasi:keyvalue/store.error" => Error,
25        },
26
27    });
28}
29
30use std::fmt::Debug;
31use std::sync::Arc;
32
33pub use omnia::FutureResult;
34use omnia::{Host, Server, State};
35use wasmtime::component::{HasData, Linker, ResourceTableError};
36use wasmtime_wasi::ResourceTable;
37
38pub use self::default_impl::KeyValueDefault;
39use self::generated::wasi::keyvalue::store::Error;
40use self::generated::wasi::keyvalue::{atomics, batch, store};
41pub use self::resource::*;
42
43/// Result type for key-value operations.
44pub type Result<T, E = Error> = anyhow::Result<T, E>;
45
46/// Host-side service for `wasi:keyvalue`.
47#[derive(Debug)]
48pub struct WasiKeyValue;
49
50impl HasData for WasiKeyValue {
51    type Data<'a> = WasiKeyValueCtxView<'a>;
52}
53
54impl<T> Host<T> for WasiKeyValue
55where
56    T: WasiKeyValueView + 'static,
57{
58    fn add_to_linker(linker: &mut Linker<T>) -> anyhow::Result<()> {
59        store::add_to_linker::<_, Self>(linker, T::keyvalue)?;
60        atomics::add_to_linker::<_, Self>(linker, T::keyvalue)?;
61        Ok(batch::add_to_linker::<_, Self>(linker, T::keyvalue)?)
62    }
63}
64
65impl<S> Server<S> for WasiKeyValue where S: State {}
66
67/// A trait which provides internal WASI Key-Value state.
68///
69/// This is implemented by the `T` in `Linker<T>` — a single type shared across
70/// all WASI components for the runtime build.
71pub trait WasiKeyValueView: Send {
72    /// Return a [`WasiKeyValueCtxView`] from mutable reference to self.
73    fn keyvalue(&mut self) -> WasiKeyValueCtxView<'_>;
74}
75
76/// View into [`WasiKeyValueCtx`] implementation and [`ResourceTable`].
77pub struct WasiKeyValueCtxView<'a> {
78    /// Mutable reference to the WASI Key-Value context.
79    pub ctx: &'a mut dyn WasiKeyValueCtx,
80
81    /// Mutable reference to table used to manage resources.
82    pub table: &'a mut ResourceTable,
83}
84
85/// A trait which provides internal WASI Key-Value context.
86///
87/// This is implemented by the resource-specific provider of Key-Value
88/// functionality. For example, an in-memory store, or a Redis-backed store.
89pub trait WasiKeyValueCtx: Debug + Send + Sync + 'static {
90    /// Open a bucket.
91    fn open_bucket(&self, identifier: String) -> FutureResult<Arc<dyn Bucket>>;
92}
93
94/// `anyhow::Error` to `Error` mapping
95impl From<anyhow::Error> for Error {
96    fn from(err: anyhow::Error) -> Self {
97        Self::Other(err.to_string())
98    }
99}
100
101/// `ResourceTableError` to `Error` mapping
102impl From<ResourceTableError> for Error {
103    fn from(err: ResourceTableError) -> Self {
104        Self::Other(err.to_string())
105    }
106}
107
108/// Implementation of the `WasiKeyValueView` trait for the store context.
109#[macro_export]
110macro_rules! omnia_wasi_view {
111    ($store_ctx:ty, $field_name:ident) => {
112        impl omnia_wasi_keyvalue::WasiKeyValueView for $store_ctx {
113            fn keyvalue(&mut self) -> omnia_wasi_keyvalue::WasiKeyValueCtxView<'_> {
114                omnia_wasi_keyvalue::WasiKeyValueCtxView {
115                    ctx: &mut self.$field_name,
116                    table: &mut self.table,
117                }
118            }
119        }
120    };
121}