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 {}