Skip to main content

fiole/
lib.rs

1#![doc = include_str!("../README.md")]
2
3use std::{convert::Infallible, marker::PhantomData};
4
5pub mod codec;
6mod database;
7mod error;
8mod keyspace;
9pub(crate) mod txn;
10
11pub use database::Database;
12pub use error::Error;
13pub use fjall::KeyspaceCreateOptions;
14pub use keyspace::Keyspace;
15pub use txn::{Readable, Rtxn, Wtxn};
16
17pub use byteorder;
18
19/// Guard to access key-value pairs.
20pub struct Guard<Key, Value>(fjall::Guard, PhantomData<(Key, Value)>);
21
22impl<Key, Value> Guard<Key, Value> {
23    #[inline]
24    pub(crate) fn new(guard: fjall::Guard) -> Self {
25        Self(guard, PhantomData)
26    }
27
28    /// Change the codec of the key.
29    #[inline]
30    #[must_use]
31    pub fn remap_key_type<NKey>(self) -> Guard<NKey, Value> {
32        Guard(self.0, PhantomData)
33    }
34
35    /// Change the codec of the value.
36    #[inline]
37    #[must_use]
38    pub fn remap_value_type<NValue>(self) -> Guard<Key, NValue> {
39        Guard(self.0, PhantomData)
40    }
41
42    /// Change the codec of the key and value.
43    #[inline]
44    #[must_use]
45    pub fn remap_types<NKey, NValue>(self) -> Guard<NKey, NValue> {
46        Guard(self.0, PhantomData)
47    }
48
49    /// For more informations, refer to [`fjall::Guard::size`].
50    #[inline]
51    #[must_use]
52    pub fn size(self) -> Result<u32, fjall::Error> {
53        self.0.size()
54    }
55}
56
57impl<Key: codec::Decode, Value> Guard<Key, Value> {
58    /// For more informations, refer to [`fjall::Guard::key`].
59    #[inline]
60    #[must_use]
61    pub fn key(self) -> Result<Key::Item, Error<Key::Error, Infallible>> {
62        let key = self.0.key().map_err(Error::Fjall)?;
63        Key::decode(key).map_err(Error::Key)
64    }
65}
66
67impl<Key, Value: codec::Decode> Guard<Key, Value> {
68    /// For more informations, refer to [`fjall::Guard::value`].
69    #[inline]
70    #[must_use]
71    pub fn value(self) -> Result<Value::Item, Error<Infallible, Value::Error>> {
72        let value = self.0.value().map_err(Error::Fjall)?;
73        Value::decode(value).map_err(Error::Value)
74    }
75}
76
77impl<Key: codec::Decode, Value: codec::Decode> Guard<Key, Value> {
78    /// For more informations, refer to [`fjall::Guard::into_inner`].
79    #[inline]
80    #[must_use]
81    pub fn into_inner(self) -> Result<(Key::Item, Value::Item), Error<Key::Error, Value::Error>> {
82        let (k, v) = self.0.into_inner().map_err(Error::Fjall)?;
83        Ok((
84            Key::decode(k).map_err(Error::Key)?,
85            Value::decode(v).map_err(Error::Value)?,
86        ))
87    }
88}
89
90/// Refer to [`fjall::Iter`] for more info.
91pub struct Iter<Key, Value>(fjall::Iter, PhantomData<(Key, Value)>);
92
93impl<Key, Value> Iter<Key, Value> {
94    #[inline]
95    pub(crate) fn new(iter: fjall::Iter) -> Self {
96        Self(iter, PhantomData)
97    }
98
99    /// Change the codec of the key.
100    #[inline]
101    pub fn remap_key_type<NKey>(self) -> Iter<NKey, Value> {
102        Iter(self.0, PhantomData)
103    }
104
105    /// Change the codec of the value.
106    #[inline]
107    pub fn remap_value_type<NValue>(self) -> Iter<Key, NValue> {
108        Iter(self.0, PhantomData)
109    }
110
111    /// Change the codec of the key and value.
112    #[inline]
113    pub fn remap_types<NKey, NValue>(self) -> Iter<NKey, NValue> {
114        Iter(self.0, PhantomData)
115    }
116}
117
118impl<Key, Value> Iterator for Iter<Key, Value> {
119    type Item = Guard<Key, Value>;
120
121    #[inline]
122    fn next(&mut self) -> Option<Self::Item> {
123        self.0.next().map(Guard::new)
124    }
125}
126
127impl<Key, Value> DoubleEndedIterator for Iter<Key, Value> {
128    #[inline]
129    fn next_back(&mut self) -> Option<Self::Item> {
130        self.0.next_back().map(Guard::new)
131    }
132}
133
134#[cfg(test)]
135mod test {
136    use fjall::KeyspaceCreateOptions;
137
138    use crate::{codec::Str, Database};
139
140    #[test]
141    fn get_from_wtxn() {
142        let dir = tempfile::tempdir().unwrap();
143        let database = Database::builder(&dir.path()).unwrap();
144        let ks = database
145            .keyspace::<Str, Str>("hello", || KeyspaceCreateOptions::default())
146            .unwrap();
147
148        // we should be able to get both from a rtxn and a wtxn with the same method and API
149        let rtxn = database.read_tx();
150        ks.get(&rtxn, "hello").unwrap();
151        let wtxn = database.write_tx().unwrap();
152        ks.get(&wtxn, "hello").unwrap();
153        drop(wtxn);
154    }
155}