wascc_actor/
keyvalue.rs

1//! # Key-Value Store
2//!
3//! This module contains the key-value store through which guest modules access
4//! the currently bound `wascap:keyvalue` capability provider
5
6use codec::keyvalue::*;
7use codec::{deserialize, serialize};
8use wapc_guest::host_call;
9use wascc_codec as codec;
10
11use crate::HandlerResult;
12
13const CAPID_KEYVALUE: &str = "wascc:keyvalue";
14
15/// An abstraction around a host runtime capability for a key-value store
16pub struct KeyValueStoreHostBinding {
17    binding: String,
18}
19
20impl Default for KeyValueStoreHostBinding {
21    fn default() -> Self {
22        KeyValueStoreHostBinding {
23            binding: "default".to_string(),
24        }
25    }
26}
27
28/// Creates a named host binding for the key-value store capability
29pub fn host(binding: &str) -> KeyValueStoreHostBinding {
30    KeyValueStoreHostBinding {
31        binding: binding.to_string(),
32    }
33}
34
35/// Creates the default host binding for the key-value store capability
36pub fn default() -> KeyValueStoreHostBinding {
37    KeyValueStoreHostBinding::default()
38}
39
40impl KeyValueStoreHostBinding {
41    /// Obtains a single value from the store
42    pub fn get(&self, key: &str) -> HandlerResult<Option<String>> {
43        let cmd = GetRequest {
44            key: key.to_string(),
45        };
46        host_call(&self.binding, CAPID_KEYVALUE, OP_GET, &serialize(cmd)?)
47            .map(|vec| {
48                let resp = deserialize::<GetResponse>(vec.as_ref()).unwrap();
49                if resp.exists {
50                    Some(resp.value)
51                } else {
52                    None
53                }
54            })
55            .map_err(|e| e.into())
56    }
57
58    /// Sets a value in the store
59    pub fn set(&self, key: &str, value: &str, expires: Option<u32>) -> HandlerResult<()> {
60        let cmd = SetRequest {
61            key: key.to_string(),
62            value: value.to_string(),
63            expires_s: expires.unwrap_or(0) as _,
64        };
65        host_call(&self.binding, CAPID_KEYVALUE, OP_SET, &serialize(cmd)?)
66            .map(|_vec| ())
67            .map_err(|e| e.into())
68    }
69
70    /// Performs an atomic increment operation
71    pub fn atomic_add(&self, key: &str, value: i32) -> HandlerResult<i32> {
72        let cmd = AddRequest {
73            key: key.to_string(),
74            value,
75        };
76        host_call(&self.binding, CAPID_KEYVALUE, OP_ADD, &serialize(cmd)?)
77            .map(|vec| {
78                let resp = deserialize::<AddResponse>(vec.as_ref()).unwrap();
79                resp.value
80            })
81            .map_err(|e| e.into())
82    }
83
84    /// Adds an item to a list at the given key
85    pub fn list_add(&self, key: &str, item: &str) -> HandlerResult<usize> {
86        let cmd = ListPushRequest {
87            key: key.to_string(),
88            value: item.to_string(),
89        };
90        host_call(&self.binding, CAPID_KEYVALUE, OP_PUSH, &serialize(cmd)?)
91            .map(|vec| {
92                let resp = deserialize::<ListResponse>(vec.as_ref()).unwrap();
93                resp.new_count as usize
94            })
95            .map_err(|e| e.into())
96    }
97
98    /// Removes an item from the list at the given key
99    pub fn list_del_item(&self, key: &str, item: &str) -> HandlerResult<usize> {
100        let cmd = ListDelItemRequest {
101            key: key.to_string(),
102            value: item.to_string(),
103        };
104        host_call(&self.binding, CAPID_KEYVALUE, OP_LIST_DEL, &serialize(cmd)?)
105            .map(|vec| {
106                let resp = deserialize::<ListResponse>(vec.as_ref()).unwrap();
107                resp.new_count as usize
108            })
109            .map_err(|e| e.into())
110    }
111
112    /// Removes the data associated with a given key, which can include lists or sets
113    pub fn del_key(&self, key: &str) -> HandlerResult<()> {
114        let cmd = DelRequest {
115            key: key.to_string(),
116        };
117        host_call(&self.binding, CAPID_KEYVALUE, OP_DEL, &serialize(cmd)?)
118            .map(|_vec| ())
119            .map_err(|e| e.into())
120    }
121
122    /// Queries a given list-type key for a range of values
123    pub fn list_range(
124        &self,
125        key: &str,
126        start: isize,
127        stop_inclusive: isize,
128    ) -> HandlerResult<Vec<String>> {
129        let cmd = ListRangeRequest {
130            key: key.to_string(),
131            start: start as i32,
132            stop: stop_inclusive as i32,
133        };
134        host_call(&self.binding, CAPID_KEYVALUE, OP_RANGE, &serialize(cmd)?)
135            .map(|vec| {
136                let resp = deserialize::<ListRangeResponse>(vec.as_ref()).unwrap();
137                resp.values
138            })
139            .map_err(|e| e.into())
140    }
141
142    /// Clears a list while leaving the key intact
143    pub fn list_clear(&self, key: &str) -> HandlerResult<()> {
144        let cmd = ListClearRequest {
145            key: key.to_string(),
146        };
147        host_call(&self.binding, CAPID_KEYVALUE, OP_CLEAR, &serialize(cmd)?)
148            .map(|_vec| ())
149            .map_err(|e| e.into())
150    }
151
152    /// Adds a value to a set at the given key
153    pub fn set_add(&self, key: &str, value: &str) -> HandlerResult<usize> {
154        let cmd = SetAddRequest {
155            key: key.to_string(),
156            value: value.to_string(),
157        };
158        host_call(&self.binding, CAPID_KEYVALUE, OP_SET_ADD, &serialize(cmd)?)
159            .map(|vec| {
160                let resp = deserialize::<SetOperationResponse>(vec.as_ref()).unwrap();
161                resp.new_count as usize
162            })
163            .map_err(|e| e.into())
164    }
165
166    /// Removes a value from the given set
167    pub fn set_remove(&self, key: &str, value: &str) -> HandlerResult<usize> {
168        let cmd = SetRemoveRequest {
169            key: key.to_string(),
170            value: value.to_string(),
171        };
172        host_call(
173            &self.binding,
174            CAPID_KEYVALUE,
175            OP_SET_REMOVE,
176            &serialize(cmd)?,
177        )
178        .map(|vec| {
179            let resp = deserialize::<SetOperationResponse>(vec.as_ref()).unwrap();
180            resp.new_count as usize
181        })
182        .map_err(|e| e.into())
183    }
184
185    /// Performs a union of sets specified by the list of keys
186    pub fn set_union(&self, keys: Vec<String>) -> HandlerResult<Vec<String>> {
187        let cmd = SetUnionRequest { keys };
188        host_call(
189            &self.binding,
190            CAPID_KEYVALUE,
191            OP_SET_UNION,
192            &serialize(cmd)?,
193        )
194        .map(|vec| {
195            let resp = deserialize::<SetQueryResponse>(vec.as_ref()).unwrap();
196            resp.values
197        })
198        .map_err(|e| e.into())
199    }
200
201    /// Performs the intersection of sets specified by the given keys
202    pub fn set_intersect(&self, keys: Vec<String>) -> HandlerResult<Vec<String>> {
203        let cmd = SetIntersectionRequest { keys };
204        host_call(
205            &self.binding,
206            CAPID_KEYVALUE,
207            OP_SET_INTERSECT,
208            &serialize(cmd)?,
209        )
210        .map(|vec| {
211            let resp = deserialize::<SetQueryResponse>(vec.as_ref()).unwrap();
212            resp.values
213        })
214        .map_err(|e| e.into())
215    }
216
217    /// Returns a list of members belonging to a given set
218    pub fn set_members(&self, key: &str) -> HandlerResult<Vec<String>> {
219        let cmd = SetQueryRequest {
220            key: key.to_string(),
221        };
222        host_call(
223            &self.binding,
224            CAPID_KEYVALUE,
225            OP_SET_QUERY,
226            &serialize(cmd)?,
227        )
228        .map(|vec| {
229            let resp = deserialize::<SetQueryResponse>(vec.as_ref()).unwrap();
230            resp.values
231        })
232        .map_err(|e| e.into())
233    }
234
235    /// Indicates whether a key exists (not that empty lists/sets may return true for their
236    /// existence if they were cleared instead of deleted)
237    pub fn exists(&self, key: &str) -> HandlerResult<bool> {
238        let cmd = KeyExistsQuery {
239            key: key.to_string(),
240        };
241        host_call(
242            &self.binding,
243            CAPID_KEYVALUE,
244            OP_KEY_EXISTS,
245            &serialize(cmd)?,
246        )
247        .map(|vec| {
248            let resp = deserialize::<GetResponse>(vec.as_ref()).unwrap();
249            resp.exists
250        })
251        .map_err(|e| e.into())
252    }
253}