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 #[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 #[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}