Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_iop_db/src/api.rs

8.9 KiB, 45 runs

created by r1870400018:399, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1use oxedyne_fe2o3_core::{
2 prelude::*,
3 alt::Override,
4 byte::{
5 FromBytes,
6 ToBytes,
7 },
8};
9#[cfg(not(target_arch = "wasm32"))]
10use oxedyne_fe2o3_crypto::enc::EncryptionScheme;
11use oxedyne_fe2o3_data::time::Timestamp;
12use oxedyne_fe2o3_hash::hash::HashScheme;
13use oxedyne_fe2o3_iop_crypto::enc::Encrypter;
14use oxedyne_fe2o3_iop_hash::api::Hasher;
15use oxedyne_fe2o3_jdat::{
16 chunk::ChunkConfig,
17 daticle::Dat,
18 id::NumIdDat,
19};
20use oxedyne_fe2o3_namex::id::InNamex;
21
22
23#[cfg(target_arch = "wasm32")]
24#[derive(Clone, Debug)]
25pub enum EncryptionScheme {}
26
27/// Metadata attached to every stored key instance.
28#[derive(Clone, Debug, Default, Eq, PartialEq)]
29pub struct Meta<
30 const UIDL: usize,
31 UID: NumIdDat<UIDL>,
32> {
33 pub time: Timestamp,
34 pub user: UID,
35}
36
37impl<
38 const UIDL: usize,
39 UID: NumIdDat<UIDL>,
40>
41 FromBytes for Meta<UIDL, UID>
42{
43 fn from_bytes(buf: &[u8]) -> Outcome<(Self, usize)> {
44 if buf.len() < Self::BYTE_LEN {
45 return Err(<Self as FromBytes>::too_few(
46 buf.len(), Self::BYTE_LEN, "Meta", file!(), line!()));
47 }
48 let (time, _n1) = res!(Timestamp::from_bytes(&buf));
49 let (user, _n_uid) = res!(UID::from_bytes(&buf[Timestamp::BYTE_LEN..]));
50 Ok((
51 Self {
52 time,
53 user,
54 },
55 Self::BYTE_LEN,
56 ))
57 }
58}
59
60impl<
61 const UIDL: usize,
62 UID: NumIdDat<UIDL>,
63>
64 ToBytes for Meta<UIDL, UID>
65{
66 fn to_bytes(&self, mut buf: Vec<u8>) -> Outcome<Vec<u8>> {
67 buf = res!(self.time.to_bytes(buf));
68 buf = res!(self.user.to_bytes(buf));
69 Ok(buf)
70 }
71}
72
73impl<
74 const UIDL: usize,
75 UID: NumIdDat<UIDL>,
76>
77 Meta<UIDL, UID>
78{
79 pub const BYTE_LEN: usize = Timestamp::BYTE_LEN + UIDL;
80
81 pub fn new(uid: UID) -> Self {
82 Self {
83 user: uid,
84 ..Default::default()
85 }
86 }
87
88 pub fn stamp_time_now(&mut self) -> Outcome<()> {
89 self.time = res!(Timestamp::now());
90 Ok(())
91 }
92
93 pub fn clone_now(&self) -> Outcome<Self> {
94 let mut result = self.clone();
95 result.time = res!(Timestamp::now());
96 Ok(result)
97 }
98}
99
100/// A database can make use of two filters for the key (hash scheme) and the value (encryption
101/// scheme). `RestSchemesOverride` is used to specify an `oxedyne_fe2o3_core::alt::Override` based on
102/// these two scheme types for encryption and key hashing (as well as an optional change in the
103/// database chunking configuration). This allows four possibilities for changing the scheme used
104/// to write and read individual (k, v) pairs:
105/// - a pass-through which defers to the current database-wide scheme,
106/// - use of a different variant of the default scheme (e.g. `EncryptionScheme`),
107/// - use of a different instance of the scheme given at invocation (e.g. `ENC`),
108/// - no scheme (i.e. the identity transformation).
109#[derive(Clone, Debug)]
110pub struct RestSchemesOverride<
111 ENC: Encrypter,
112 KH: Hasher,
113>{
114 pub enc: Override<EncryptionScheme, ENC>,
115 pub hash: Override<HashScheme, KH>,
116 pub chnk: Option<ChunkConfig>,
117}
118
119impl<
120 ENC: Encrypter,
121 KH: Hasher,
122>
123 Default for RestSchemesOverride<ENC, KH>
124{
125 fn default() -> Self {
126 Self {
127 enc: Override::PassThrough,
128 hash: Override::PassThrough,
129 chnk: None,
130 }
131 }
132}
133
134impl<
135 ENC: Encrypter,
136 KH: Hasher,
137>
138 RestSchemesOverride<ENC, KH>
139{
140 /// Expresses the intention not to override the database defaults.
141 pub fn none() -> Self {
142 Self::default()
143 }
144
145 pub fn encrypter(&self) -> &Override<EncryptionScheme, ENC> { &self.enc }
146 pub fn key_hasher(&self) -> &Override<HashScheme, KH> { &self.hash }
147 pub fn chunk_config(&self) -> &Option<ChunkConfig> { &self.chnk }
148
149 pub fn set_encrypter(mut self, enc: Override<EncryptionScheme, ENC>) -> Self {
150 self.enc = enc;
151 self
152 }
153 pub fn set_key_hasher(mut self, hash: Override<HashScheme, KH>) -> Self {
154 self.hash = hash;
155 self
156 }
157 pub fn set_chunk_config(mut self, chnk: Option<ChunkConfig>) -> Self {
158 self.chnk = chnk;
159 self
160 }
161}
162
163#[derive(Clone, Debug, Default)]
164pub struct ScanOpts {
165 pub prefix: Option<Dat>,
166 pub limit: Option<usize>,
167 pub include_values: bool,
168 pub chunk_data_only: bool, // emit only a chunked value's internal chunk-data keys (the inverse of the default)
169}
170
171impl ScanOpts {
172 pub fn all() -> Self {
173 Self::default()
174 }
175
176 pub fn with_str_prefix(prefix: impl Into<String>) -> Self {
177 Self {
178 prefix: Some(Dat::Str(prefix.into())),
179 limit: None,
180 include_values: false,
181 chunk_data_only: false,
182 }
183 }
184
185 pub fn include_values(mut self, yes: bool) -> Self {
186 self.include_values = yes;
187 self
188 }
189
190 pub fn limit(mut self, n: usize) -> Self {
191 self.limit = Some(n);
192 self
193 }
194
195 /// Inverts which records a scan emits: with this set the scan returns only the internal
196 /// chunk-data keys of chunked values (chunk index `>= 1`) and elides the main user keys a
197 /// default scan returns. An orphan sweep uses it to enumerate every chunk-data record and
198 /// subtract the set still referenced by a live bunch key.
199 pub fn chunk_data_only(mut self, yes: bool) -> Self {
200 self.chunk_data_only = yes;
201 self
202 }
203}
204
205/// A minimal, universal and synchronous (blocking) interface for a database.
206///
207pub trait Database<
208 const UIDL: usize, // User identifier byte length.
209 UID: NumIdDat<UIDL>, // User identifier.
210 ENC: Encrypter, // Symmetric encryption of data at rest.
211 KH: Hasher, // Hashes database keys.
212>:
213 std::fmt::Debug
214 + InNamex
215 + Send
216 + Sync
217{
218 /// Insert a key-value pair of `Daticle`s into the database. Returns whether the key already
219 /// exists, and the number of chunks.
220 fn insert(
221 &self,
222 key: Dat,
223 val: Dat,
224 user: UID,
225 or: Option<&RestSchemesOverride<ENC, KH>>,
226 )
227 -> Outcome<(bool, usize)>;
228
229 /// Return a possible value, along with the key metadata.
230 fn get(
231 &self,
232 key: &Dat,
233 or: Option<&RestSchemesOverride<ENC, KH>>,
234 )
235 -> Outcome<Option<(Dat, Meta<UIDL, UID>)>>;
236
237 /// Deletes the given key and its value from the database, or at least marks it for deletion.
238 fn delete(
239 &self,
240 key: &Dat,
241 user: UID,
242 or: Option<&RestSchemesOverride<ENC, KH>>,
243 )
244 -> Outcome<bool>;
245
246 fn scan(
247 &self,
248 opts: &ScanOpts,
249 or: Option<&RestSchemesOverride<ENC, KH>>,
250 )
251 -> Outcome<Vec<(Dat, Dat, Meta<UIDL, UID>)>>;
252}
253
254#[derive(Debug)]
255pub struct NoDatabase<
256 const UIDL: usize,
257 UID: NumIdDat<UIDL>,
258 ENC: Encrypter,
259 KH: Hasher,
260> {
261 uid: std::marker::PhantomData<UID>,
262 enc: std::marker::PhantomData<ENC>,
263 kh: std::marker::PhantomData<KH>,
264}
265
266impl<
267 const UIDL: usize,
268 UID: NumIdDat<UIDL>,
269 ENC: Encrypter,
270 KH: Hasher,
271>
272 Default for NoDatabase<UIDL, UID, ENC, KH>
273{
274 fn default() -> Self {
275 Self {
276 uid: std::marker::PhantomData,
277 enc: std::marker::PhantomData,
278 kh: std::marker::PhantomData,
279 }
280 }
281}
282
283impl<
284 const UIDL: usize,
285 UID: NumIdDat<UIDL>,
286 ENC: Encrypter,
287 KH: Hasher,
288>
289 InNamex for NoDatabase<UIDL, UID, ENC, KH>
290{
291 fn name_id(&self) -> Outcome<oxedyne_fe2o3_namex::id::NamexId> {
292 Err(err!(
293 "There is no database here, so it has no name.";
294 Invalid, Missing))
295 }
296}
297
298impl<
299 const UIDL: usize,
300 UID: NumIdDat<UIDL>,
301 ENC: Encrypter,
302 KH: Hasher,
303>
304 Database<UIDL, UID, ENC, KH> for NoDatabase<UIDL, UID, ENC, KH>
305{
306 fn insert(
307 &self,
308 _key: Dat,
309 _val: Dat,
310 _user: UID,
311 _or: Option<&RestSchemesOverride<ENC, KH>>,
312 )
313 -> Outcome<(bool, usize)>
314 {
315 Err(err!("There is no database here to insert into."; Invalid, Missing))
316 }
317
318 fn get(
319 &self,
320 _key: &Dat,
321 _or: Option<&RestSchemesOverride<ENC, KH>>,
322 )
323 -> Outcome<Option<(Dat, Meta<UIDL, UID>)>>
324 {
325 Err(err!("There is no database here to read from."; Invalid, Missing))
326 }
327
328 fn delete(
329 &self,
330 _key: &Dat,
331 _user: UID,
332 _or: Option<&RestSchemesOverride<ENC, KH>>,
333 )
334 -> Outcome<bool>
335 {
336 Err(err!("There is no database here to delete from."; Invalid, Missing))
337 }
338
339 fn scan(
340 &self,
341 _opts: &ScanOpts,
342 _or: Option<&RestSchemesOverride<ENC, KH>>,
343 )
344 -> Outcome<Vec<(Dat, Dat, Meta<UIDL, UID>)>>
345 {
346 Err(err!("There is no database here to scan."; Invalid, Missing))
347 }
348}