redb_bincode/
lib.rs

1#![doc = include_str!("../README.md")]
2
3mod access_guard;
4mod database;
5mod range;
6mod readable_table;
7mod sort;
8mod tx;
9
10use std::borrow::Borrow;
11use std::cell::UnsafeCell;
12use std::marker::PhantomData;
13use std::{fmt, ops};
14
15pub use access_guard::*;
16pub use database::*;
17pub use range::*;
18pub use readable_table::*;
19use redb::ReadableTable as _;
20pub use redb::StorageError;
21pub use sort::*;
22pub use tx::*;
23
24pub const BINCODE_CONFIG: bincode::config::Configuration<bincode::config::BigEndian> =
25    bincode::config::standard()
26        .with_big_endian()
27        .with_variable_int_encoding();
28
29thread_local! {
30    pub static ENCODE_KEY: std::cell::UnsafeCell<Vec<u8>> = const { std::cell::UnsafeCell::new(vec![]) };
31    pub static ENCODE_VALUE: std::cell::UnsafeCell<Vec<u8>> = const { std::cell::UnsafeCell::new(vec![]) };
32}
33
34unsafe fn with_encode_key_buf<R>(f: impl FnOnce(&mut Vec<u8>) -> R) -> R {
35    // https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html#memory-layout
36    #[allow(clippy::mut_from_ref)]
37    unsafe fn get_mut<T>(ptr: &UnsafeCell<T>) -> &mut T {
38        unsafe { &mut *ptr.get() }
39    }
40
41    ENCODE_KEY.with(|buf| {
42        let buf = unsafe { get_mut(buf) };
43        let res = f(buf);
44        buf.clear();
45        res
46    })
47}
48unsafe fn with_encode_value_buf<R>(f: impl FnOnce(&mut Vec<u8>) -> R) -> R {
49    // https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html#memory-layout
50    #[allow(clippy::mut_from_ref)]
51    unsafe fn get_mut<T>(ptr: &UnsafeCell<T>) -> &mut T {
52        unsafe { &mut *ptr.get() }
53    }
54
55    ENCODE_VALUE.with(|buf| {
56        let buf = unsafe { get_mut(buf) };
57        let res = f(buf);
58        buf.clear();
59        res
60    })
61}
62
63pub struct ReadOnlyTable<K, V, S = Lexicographical>
64where
65    S: SortOrder + fmt::Debug + 'static,
66{
67    inner: redb::ReadOnlyTable<sort::SortKey<S>, &'static [u8]>,
68    _k: PhantomData<K>,
69    _v: PhantomData<V>,
70}
71
72impl<K, V, S> ReadOnlyTable<K, V, S>
73where
74    S: SortOrder + fmt::Debug + 'static,
75    K: bincode::Encode + bincode::Decode<()>,
76    V: bincode::Encode + bincode::Decode<()>,
77{
78    pub fn as_raw(&self) -> &redb::ReadOnlyTable<sort::SortKey<S>, &'static [u8]> {
79        &self.inner
80    }
81
82    #[allow(clippy::type_complexity)]
83    pub fn first(
84        &self,
85    ) -> Result<Option<(AccessGuard<'_, K, SortKey<S>>, AccessGuard<'_, V>)>, StorageError> {
86        Ok(self
87            .inner
88            .first()?
89            .map(|(k, v)| (AccessGuard::from(k), AccessGuard::from(v))))
90    }
91
92    #[allow(clippy::type_complexity)]
93    pub fn last(
94        &self,
95    ) -> Result<Option<(AccessGuard<'_, K, SortKey<S>>, AccessGuard<'_, V>)>, StorageError> {
96        Ok(self
97            .inner
98            .last()?
99            .map(|(k, v)| (AccessGuard::from(k), AccessGuard::from(v))))
100    }
101
102    pub fn range<'a, Q>(
103        &self,
104        range: impl ops::RangeBounds<Q> + 'a,
105    ) -> Result<Range<'_, K, V, SortKey<S>>, StorageError>
106    where
107        K: Borrow<Q>,
108        Q: bincode::Encode + ?Sized,
109    {
110        let redb_range = unsafe {
111            with_encode_key_buf(|start_bound_buf| {
112                let start_bound_size = range.start_bound().map(|bound| {
113                    bincode::encode_into_std_write(bound, start_bound_buf, BINCODE_CONFIG)
114                        .expect("encoding can't fail")
115                });
116
117                with_encode_value_buf(|end_bound_buf| {
118                    let end_bound_size = range.end_bound().map(|bound| {
119                        bincode::encode_into_std_write(bound, end_bound_buf, BINCODE_CONFIG)
120                            .expect("encoding can't fail")
121                    });
122
123                    let start_bound =
124                        start_bound_size.map(|size| SortKey(&start_bound_buf[..size]));
125                    let end_bound = end_bound_size.map(|size| SortKey(&end_bound_buf[..size]));
126                    self.inner.range((start_bound, end_bound))
127                })
128            })?
129        };
130        Ok(Range::from(redb_range))
131    }
132
133    pub fn get<Q>(&self, key: &Q) -> Result<Option<AccessGuard<'_, V>>, StorageError>
134    where
135        K: Borrow<Q>,
136        Q: bincode::Encode + ?Sized,
137    {
138        unsafe {
139            Ok(with_encode_key_buf(|buf| {
140                let size = bincode::encode_into_std_write(key, buf, BINCODE_CONFIG)
141                    .expect("encoding can't fail");
142                self.inner.get(&buf[..size])
143            })?
144            .map(AccessGuard::from))
145        }
146    }
147}
148
149pub struct Table<'txn, K, V, S = Lexicographical>
150where
151    S: SortOrder + fmt::Debug + 'static,
152{
153    inner: redb::Table<'txn, sort::SortKey<S>, &'static [u8]>,
154    _k: PhantomData<K>,
155    _v: PhantomData<V>,
156}
157
158impl<'txn, K, V, S> Table<'txn, K, V, S>
159where
160    S: SortOrder + fmt::Debug + 'static,
161    K: bincode::Encode + bincode::Decode<()>,
162    V: bincode::Encode + bincode::Decode<()>,
163{
164    pub fn as_raw(&self) -> &redb::Table<sort::SortKey<S>, &'static [u8]> {
165        &self.inner
166    }
167    pub fn as_raw_mut(&mut self) -> &'txn mut redb::Table<'_, sort::SortKey<S>, &'static [u8]> {
168        &mut self.inner
169    }
170
171    #[allow(clippy::type_complexity)]
172    pub fn first(
173        &self,
174    ) -> Result<Option<(AccessGuard<'_, K, SortKey<S>>, AccessGuard<'_, V>)>, StorageError> {
175        Ok(self
176            .inner
177            .first()?
178            .map(|(k, v)| (AccessGuard::from(k), AccessGuard::from(v))))
179    }
180
181    #[allow(clippy::type_complexity)]
182    pub fn last(
183        &self,
184    ) -> Result<Option<(AccessGuard<'_, K, SortKey<S>>, AccessGuard<'_, V>)>, StorageError> {
185        Ok(self
186            .inner
187            .last()?
188            .map(|(k, v)| (AccessGuard::from(k), AccessGuard::from(v))))
189    }
190
191    pub fn range<'a, Q>(
192        &self,
193        range: impl ops::RangeBounds<Q> + 'a,
194    ) -> Result<Range<'_, K, V, SortKey<S>>, StorageError>
195    where
196        K: Borrow<Q>,
197        Q: bincode::Encode + ?Sized,
198    {
199        let redb_range = unsafe {
200            with_encode_key_buf(|start_bound_buf| {
201                let start_bound_size = range.start_bound().map(|bound| {
202                    bincode::encode_into_std_write(bound, start_bound_buf, BINCODE_CONFIG)
203                        .expect("encoding can't fail")
204                });
205
206                with_encode_value_buf(|end_bound_buf| {
207                    let end_bound_size = range.end_bound().map(|bound| {
208                        bincode::encode_into_std_write(bound, end_bound_buf, BINCODE_CONFIG)
209                            .expect("encoding can't fail")
210                    });
211
212                    let start_bound =
213                        start_bound_size.map(|size| SortKey(&start_bound_buf[..size]));
214                    let end_bound = end_bound_size.map(|size| SortKey(&end_bound_buf[..size]));
215                    self.inner.range((start_bound, end_bound))
216                })
217            })?
218        };
219        Ok(Range::from(redb_range))
220    }
221
222    pub fn get<Q>(&self, key: &Q) -> Result<Option<AccessGuard<'_, V>>, StorageError>
223    where
224        K: Borrow<Q>,
225        Q: bincode::Encode + ?Sized,
226    {
227        unsafe {
228            Ok(with_encode_key_buf(|buf| {
229                let size = bincode::encode_into_std_write(key, buf, BINCODE_CONFIG)
230                    .expect("encoding can't fail");
231                self.inner.get(&buf[..size])
232            })?
233            .map(AccessGuard::from))
234        }
235    }
236
237    pub fn insert<KQ, VQ>(
238        &mut self,
239        key: &KQ,
240        value: &VQ,
241    ) -> Result<Option<AccessGuard<'_, V>>, StorageError>
242    where
243        K: Borrow<KQ>,
244        V: Borrow<VQ>,
245        KQ: bincode::Encode + ?Sized,
246        VQ: bincode::Encode + ?Sized,
247    {
248        Ok(unsafe {
249            with_encode_key_buf(|key_buf| {
250                let key_size = bincode::encode_into_std_write(key, key_buf, BINCODE_CONFIG)
251                    .expect("encoding can't fail");
252
253                with_encode_value_buf(|value_buf| {
254                    let value_size =
255                        bincode::encode_into_std_write(value, value_buf, BINCODE_CONFIG)
256                            .expect("encoding can't fail");
257
258                    self.inner
259                        .insert(&key_buf[..key_size], &value_buf[..value_size])
260                })
261            })
262        }?
263        .map(AccessGuard::from))
264    }
265
266    pub fn remove<KQ>(&mut self, key: &KQ) -> Result<Option<AccessGuard<'_, V>>, StorageError>
267    where
268        K: Borrow<KQ>,
269        KQ: bincode::Encode + ?Sized,
270    {
271        Ok(unsafe {
272            with_encode_key_buf(|key_buf| {
273                let key_size = bincode::encode_into_std_write(key, key_buf, BINCODE_CONFIG)
274                    .expect("encoding can't fail");
275                self.inner.remove(&key_buf[..key_size])
276            })
277        }?
278        .map(AccessGuard::from))
279    }
280
281    pub fn retain<F>(&mut self, mut predicate: F) -> Result<(), StorageError>
282    where
283        F: for<'f> FnMut(&'f K, &'f V) -> bool,
284    {
285        self.inner.retain(|raw_key, raw_val| {
286            let k = bincode::decode_from_slice(raw_key, BINCODE_CONFIG)
287                .map(|k| k.0)
288                .expect("Invalid encoding");
289            let v = bincode::decode_from_slice(raw_val, BINCODE_CONFIG)
290                .map(|v| v.0)
291                .expect("Invalid encoding");
292            predicate(&k, &v)
293        })
294    }
295
296    pub fn retain_in<'a, Q, F>(
297        &mut self,
298        range: impl ops::RangeBounds<Q> + 'a,
299        mut predicate: F,
300    ) -> Result<(), StorageError>
301    where
302        K: Borrow<Q>,
303        Q: bincode::Encode + ?Sized,
304        F: for<'f> FnMut(&'f K, &'f V) -> bool,
305    {
306        unsafe {
307            with_encode_key_buf(|start_bound_buf| {
308                let start_bound_size = range.start_bound().map(|bound| {
309                    bincode::encode_into_std_write(bound, start_bound_buf, BINCODE_CONFIG)
310                        .expect("encoding can't fail")
311                });
312
313                with_encode_value_buf(|end_bound_buf| {
314                    let end_bound_size = range.end_bound().map(|bound| {
315                        bincode::encode_into_std_write(bound, end_bound_buf, BINCODE_CONFIG)
316                            .expect("encoding can't fail")
317                    });
318
319                    let start_bound =
320                        start_bound_size.map(|size| SortKey(&start_bound_buf[..size]));
321                    let end_bound = end_bound_size.map(|size| SortKey(&end_bound_buf[..size]));
322                    self.inner
323                        .retain_in((start_bound, end_bound), |raw_key, raw_val| {
324                            let k = bincode::decode_from_slice(raw_key, BINCODE_CONFIG)
325                                .map(|k| k.0)
326                                .expect("Invalid encoding");
327                            let v = bincode::decode_from_slice(raw_val, BINCODE_CONFIG)
328                                .map(|v| v.0)
329                                .expect("Invalid encoding");
330                            predicate(&k, &v)
331                        })?;
332
333                    Ok(())
334                })
335            })
336        }
337    }
338}