leveldb_orm/
lib.rs

1//! An ORM wrapper for Rust [`leveldb`] [`leveldb::database::kv::KV`] APIs. Use [`bincode`] to encoder / decoder key and object.
2//!
3//! [`leveldb::database::kv::KV`]: http://skade.github.io/leveldb/leveldb/database/kv/trait.KV.html
4//! [`leveldb`]: https://crates.io/crates/leveldb
5//!
6//! #### Example
7//! This example shows the quickest way to get started with feature `macros`
8//!
9//! ```toml
10//! [dependencies]
11//! leveldb = "0.8"
12//! leveldb-orm = { version = "0.1", features = ["macros"]}
13//! serde = { version = "1.0", features = ["derive"] }
14//! ```
15//!
16//! ```rust
17//! #[cfg(feature = "macros")]
18//! mod example {
19//!     use leveldb::database::Database;
20//!     use leveldb::options::Options;
21//!     use leveldb_orm::{KVOrm, KeyOrm, LeveldbOrm};
22//!     use serde::{Deserialize, Serialize};
23//!
24//!     #[derive(LeveldbOrm, Serialize, Deserialize)]
25//!     #[leveldb_key(executable, args)]
26//!     pub struct Command {
27//!         pub executable: u8,
28//!         pub args: Vec<String>,
29//!         pub current_dir: Option<String>,
30//!     }
31//!
32//!     fn main() {
33//!         let cmd = Command {
34//!             executable: 1,
35//!             args: vec!["arg1".into(), "arg2".into(), "arg3".into()],
36//!             current_dir: Some("\\dir".into()),
37//!         };
38//!
39//!         let mut options = Options::new();
40//!         options.create_if_missing = true;
41//!         let database = Database::open(std::path::Path::new("./mypath"), options).unwrap();
42//!
43//!         cmd.put(&database).unwrap();
44//!
45//!         let key = Command::encode_key((&cmd.executable, &cmd.args)).unwrap();
46//!         // or `let key = cmd.key().unwrap();`
47//!         Command::get(&database, &key).unwrap();
48//!
49//!         Command::delete(&database, false, &key).unwrap();
50//!     }
51//! }
52//! ```
53
54#[cfg(feature = "macros")]
55pub use ::leveldb_orm_derive::LeveldbOrm;
56
57use leveldb::database::batch::Writebatch;
58use leveldb::database::Database;
59use leveldb::kv::KV;
60use leveldb::options::ReadOptions;
61use serde::de::DeserializeOwned;
62use serde::Serialize;
63use std::marker::PhantomData;
64
65pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync + 'static>>;
66
67/// The key for leveldb, which impled [`db_key::Key`]. (db-key 0.0.5 only impl it for i32)
68/// You can serialize you key to Vec<u8> / &\[u8\] and into EncodedKey.
69///
70/// [`db_key::Key`]: https://crates.io/crates/db-key/0.0.5
71#[derive(Debug, PartialEq)]
72pub struct EncodedKey<T: 'static> {
73    pub inner: Vec<u8>,
74    phantom: PhantomData<T>,
75}
76
77impl<T> db_key::Key for EncodedKey<T> {
78    #[inline]
79    fn from_u8(key: &[u8]) -> Self {
80        EncodedKey {
81            inner: key.into(),
82            phantom: PhantomData,
83        }
84    }
85    #[inline]
86    fn as_slice<S, F: Fn(&[u8]) -> S>(&self, f: F) -> S {
87        f(&self.inner)
88    }
89}
90
91impl<T> From<Vec<u8>> for EncodedKey<T> {
92    #[inline]
93    fn from(inner: Vec<u8>) -> Self {
94        EncodedKey {
95            inner,
96            phantom: PhantomData,
97        }
98    }
99}
100
101impl<T> From<&[u8]> for EncodedKey<T> {
102    #[inline]
103    fn from(v: &[u8]) -> Self {
104        EncodedKey {
105            inner: v.into(),
106            phantom: PhantomData,
107        }
108    }
109}
110
111/// Interface of key encode / decode
112pub trait KeyOrm<'a>: Sized {
113    type KeyType: DeserializeOwned;
114    type KeyTypeRef: Serialize + 'a;
115
116    /// Without `macros` feature, you can impl `encode_key` by yourself
117    #[cfg(not(feature = "macros"))]
118    fn encode_key(key: Self::KeyTypeRef) -> Result<EncodedKey<Self>>;
119
120    /// With `macros` feature, the key encodes by [`bincode`]
121    #[cfg(feature = "macros")]
122    #[inline]
123    fn encode_key(key: Self::KeyTypeRef) -> Result<EncodedKey<Self>> {
124        bincode::serialize(&key)
125            .map(EncodedKey::from)
126            .map_err(|e| e.into())
127    }
128
129    /// Without `macros` feature, you can impl `decode_key` by yourself
130    #[cfg(not(feature = "macros"))]
131    fn decode_key(data: &EncodedKey<Self>) -> Result<Self::KeyType>;
132
133    /// With `macros` feature, the key decodes by [`bincode`]
134    #[cfg(feature = "macros")]
135    #[inline]
136    fn decode_key(data: &EncodedKey<Self>) -> Result<Self::KeyType> {
137        bincode::deserialize(&data.inner).map_err(|e| e.into())
138    }
139
140    /// `#[derive(LeveldbOrm)]` + `#[leveldb_key(...)]` could auto impl this function, without derive macro you can impl it manully
141    fn key(&self) -> Result<EncodedKey<Self>>;
142}
143
144/// An orm version of [`leveldb::database::kv::KV`](http://skade.github.io/leveldb/leveldb/database/kv/trait.KV.html)
145pub trait KVOrm<'a>: KeyOrm<'a> + Serialize + DeserializeOwned {
146    /// Encode `Self` by [`bincode`]
147    #[inline]
148    fn encode(&self) -> Result<Vec<u8>> {
149        bincode::serialize(self).map_err(|e| e.into())
150    }
151
152    /// Decode to `Self` by [`bincode`]
153    #[inline]
154    fn decode(data: &[u8]) -> Result<Self> {
155        bincode::deserialize(data).map_err(|e| e.into())
156    }
157
158    /// Refer to [leveldb::database::kv::KV::put](http://skade.github.io/leveldb/leveldb/database/kv/trait.KV.html#tymethod.put)
159    fn put_sync(&self, db: &Database<EncodedKey<Self>>, sync: bool) -> Result<()> {
160        let key = self.key()?;
161        let value = self.encode()?;
162        db.put(leveldb::options::WriteOptions { sync }, key, &value)
163            .map_err(|e| e.into())
164    }
165
166    /// With default sync = false
167    fn put(&self, db: &Database<EncodedKey<Self>>) -> Result<()> {
168        self.put_sync(db, false)
169    }
170
171    /// Refer to [leveldb::database::kv::KV::get](http://skade.github.io/leveldb/leveldb/database/kv/trait.KV.html#tymethod.get)
172    fn get_with_option(
173        db: &Database<EncodedKey<Self>>,
174        options: ReadOptions<'a, EncodedKey<Self>>,
175        key: &EncodedKey<Self>,
176    ) -> Result<Option<Self>> {
177        if let Some(data) = db.get(options, key)? {
178            Ok(Some(bincode::deserialize(&data)?))
179        } else {
180            Ok(None)
181        }
182    }
183
184    /// With default `ReadOptions`
185    fn get(db: &Database<EncodedKey<Self>>, key: &EncodedKey<Self>) -> Result<Option<Self>> {
186        Self::get_with_option(db, ReadOptions::new(), key)
187    }
188
189    /// Refer to [leveldb::database::kv::KV::delete](http://skade.github.io/leveldb/leveldb/database/kv/trait.KV.html#tymethod.delete)
190    fn delete(db: &Database<EncodedKey<Self>>, sync: bool, key: &EncodedKey<Self>) -> Result<()> {
191        db.delete(leveldb::options::WriteOptions { sync }, key)
192            .map_err(|e| e.into())
193    }
194}
195
196/// An orm version of [`leveldb::database::batch::Writebatch::put`](http://skade.github.io/leveldb/leveldb/database/batch/struct.Writebatch.html#method.put)
197pub trait WritebatchOrm<'a>: KVOrm<'a> {
198    fn put_batch(&self, batch: &mut Writebatch<EncodedKey<Self>>) -> Result<()> {
199        let key = self.key()?;
200        let value = self.encode()?;
201        batch.put(key, &value);
202        Ok(())
203    }
204}
205
206impl<'a, T: KeyOrm<'a> + Serialize + DeserializeOwned> KVOrm<'a> for T {}
207impl<'a, T: KVOrm<'a>> WritebatchOrm<'a> for T {}