1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
define_api_id!(0x2110_e04a_32df_fab1, "storage-v1");
use crate::FFIResult;
/// Handle to a store
pub type StoreHandle = u64;
/// Handle to a async get operation on a store
pub type AsyncGetHandle = u64;
#[ark_api_macros::ark_bindgen(imports = "ark-storage-v1")]
mod storage {
use super::*;
/// Storage realm, where a store exists.
#[repr(u32)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum StoreRealm {
/// Store is not persisted and only available while open in the current module instance.
///
/// This is mostly useful for testing purposes, or possibly to be able to "swap" out and
/// use more than 2 GB of memory in a Wasm module.
ModuleInstance = 1,
/// Store is persisted only on the local device, store names are device-wide for any module
/// to access.
///
/// This is useful, for instance, for testing purposes before creating a global cache, as
/// well as for keeping some local caches in modules.
DeviceShared = 2,
/// Store is persisted only on the local device, store names are device-wide for any module
/// to access.
///
/// This is useful, for instance, for testing purposes before creating a global cache, as
/// well as for keeping some local caches in modules.
DeviceUser = 4,
/// Store is persisted on the local device and asynchronously and automatically
/// synchronized globally for other users.
GlobalShared = 3,
/// Store is specific to a single user, is persisted on the local device as well
/// as asynchronously automatically synchronized globally.
///
/// This means that each user will get their own version of a store with the same name
GlobalUser = 5,
}
/// Is this store sync or async?
#[repr(u32)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum StoreMode {
/// All the store methods are sync. Upon creation, there's an initial refresh of all the
/// keys *and* values, spawned in the background. The first method call will block on this
/// initial refresh being done.
///
/// As a matter of fact, this will fetch all the values, which can be quite slow for large
/// stores. It is recommended to only use this for small stores, and to request open them
/// as soon as possible in the applet's life cycle, e.g. in the `ark_initialize`
/// entrypoint.
///
/// Individual values are expected to be obtained through `immediate_get`.
/// Using `async_get` on such a store will work fine, but add unnecessary overhead in terms
/// of performance and it will be more tedious.
Sync,
/// The store provides an `async get` method, and all other methods are sync. Upon
/// creation, there's an initial refresh of all the keys only, spawned in the background.
/// The first method call will block on this initial refresh being done.
///
/// Individual values are expected to be obtained through `async_get`. Using
/// `immediate_get` on such a store will block the main thread until the value is done
/// downloading.
Async,
}
extern "C" {
/// Open a store and make it available for the module
///
/// This can be a very expensive operation for [`StoreRealm::Global]` as it will synchronize and download latest data.
/// Prefer to call this early in module initialization
#[deprecated_infallible]
pub fn store_open(realm: StoreRealm, name: &str) -> StoreHandle;
/// Open a store and make it available for the module
///
/// This can be a very expensive operation for [`StoreRealm::Global]` as it will synchronize and download latest data.
/// Prefer to call this early in module initialization
///
/// Note: This does not support [`StoreRealm::DeviceUser`] or [`StoreRealm::GlobalUser`], use `store_open3` for that
pub fn store_open2(realm: StoreRealm, mode: StoreMode, name: &str) -> StoreHandle;
/// Open a store and make it available for the module
///
/// This can be a very expensive operation for [`StoreRealm::Global]` as it will synchronize and download latest data.
/// Prefer to call this early in module initialization
pub fn store_open3(
realm: StoreRealm,
realm_user_id: &[u8],
mode: StoreMode,
name: &str,
) -> StoreHandle;
/// Close a store
#[deprecated_infallible]
pub fn store_close(handle: StoreHandle);
/// Set a key value in a store
///
/// This is a fast call that updates the store in-memory or on-disk
#[deprecated_infallible]
pub fn immediate_insert(store: StoreHandle, key: &[u8], value: &[u8]);
/// Remove key value in a store
///
/// This is a fast call that updates the store in-memory or on-disk
#[deprecated_infallible]
pub fn immediate_remove(store: StoreHandle, key: &[u8]);
/// Get the value of a key, for a store opened in `StoreMode::Sync` mode.
///
/// This is a fast call, as a sync store synchronizes all the data in real-time in the
/// background.
///
/// Using this method with a store opened in `StoreMode::Async` mode will block the main
/// thread, waiting for the value to be downloaded if it is not present in the local cache.
/// It is recommended to use `async_get` for such stores.
///
/// # Return
///
/// If a key is found, will return a vector filled with the entry encoded as plain bytes.
/// If a key is not found, will fail with `NotFound`.
pub fn immediate_get(store: StoreHandle, key: &[u8]) -> FFIResult<Vec<u8>>;
/// Get list of all keys in a single byte buffer
///
/// This can be a potentially quite large list although only contains the keys, not the values.
///
/// # Return
///
/// The list of all the keys is returned in a binary blob.
/// The data is formatted in a single binary buffer that starts with a `u32` count of keys and then each
/// key is following with a `u32` length of the key and then the contents of the key
#[deprecated_infallible]
pub fn immediate_list(store: StoreHandle) -> Vec<u8>;
/// Get the value of a key, for a store opened in `StoreMode::Async` mode.
///
/// This returns a handle to an asynchronous operation that will first try to retrieve a
/// cached version of the value, or fetch it from a remote store if not found.
///
/// The final value may be retrieved with `async_get_is_ready`.
///
/// Using this method with a store opened in `StoreMode::Sync` mode will work just fine,
/// but add unnecessary overhead and is more tedious; prefer using `immediate_get` for such
/// stores.
pub fn async_get(store: StoreHandle, key: &[u8]) -> AsyncGetHandle;
/// Attempts to read the value requested by a previous `async_get` call.
///
/// # Return
///
/// If the async request is done:
///
/// - If a key is found, will return a vector filled with the entry encoded as plain bytes.
/// - If a key is not found, will fail with `NotFound`.
///
/// If the async request is not done yet, will fail with `Unavailable`.
pub fn async_get_ready(handle: AsyncGetHandle) -> FFIResult<Vec<u8>>;
}
}
pub use storage::*;