1use super::bytes::Bytes;
2use super::comparator::{create_comparator, Comparator};
3use super::error::Error;
4use super::key::IntoLevelDBKey;
5use super::options::*;
6use cruzbit_leveldb_sys::*;
7use libc::{c_char, size_t};
8use std::ffi::CString;
9use std::path::Path;
10use std::ptr;
11
12#[allow(missing_docs)]
13#[derive(Debug)]
14pub(crate) struct RawDB {
15 pub(crate) ptr: *mut leveldb_t,
16}
17
18#[allow(missing_docs)]
19impl Drop for RawDB {
20 fn drop(&mut self) {
21 unsafe {
22 leveldb_close(self.ptr);
23 }
24 }
25}
26
27#[allow(missing_docs)]
28#[derive(Debug)]
29pub(crate) struct RawComparator {
30 ptr: *mut leveldb_comparator_t,
31}
32
33#[allow(missing_docs)]
34impl Drop for RawComparator {
35 fn drop(&mut self) {
36 unsafe {
37 leveldb_comparator_destroy(self.ptr);
38 }
39 }
40}
41
42#[derive(Debug)]
43pub struct Database {
44 pub(crate) database: RawDB,
45 #[allow(dead_code)]
48 pub(crate) comparator: Option<RawComparator>,
49}
50
51unsafe impl Sync for Database {}
52unsafe impl Send for Database {}
53
54impl Database {
55 fn new(database: *mut leveldb_t, comparator: Option<*mut leveldb_comparator_t>) -> Database {
56 let raw_comp = comparator.map(|p| RawComparator { ptr: p });
57
58 Database {
59 database: RawDB { ptr: database },
60 comparator: raw_comp,
61 }
62 }
63
64 pub fn open(name: &Path, options: &Options) -> Result<Database, Error> {
69 let mut error = ptr::null_mut();
70
71 unsafe {
72 let c_string = CString::new(name.to_str().unwrap()).unwrap();
73 let c_options = c_options(options, None);
74 let db = leveldb_open(
75 c_options as *const leveldb_options_t,
76 c_string.as_bytes_with_nul().as_ptr() as *const c_char,
77 &mut error,
78 );
79 leveldb_options_destroy(c_options);
80
81 if error.is_null() {
82 Ok(Database::new(db, None))
83 } else {
84 Err(Error::new_from_char(error))
85 }
86 }
87 }
88
89 pub fn open_with_comparator<C: Comparator>(
98 name: &Path,
99 options: &Options,
100 comparator: C,
101 ) -> Result<Database, Error> {
102 let mut error = ptr::null_mut();
103 let comp_ptr = create_comparator(Box::new(comparator));
104 unsafe {
105 let c_string = CString::new(name.to_str().unwrap()).unwrap();
106 let c_options = c_options(options, Some(comp_ptr));
107 let db = leveldb_open(
108 c_options as *const leveldb_options_t,
109 c_string.as_bytes_with_nul().as_ptr() as *const c_char,
110 &mut error,
111 );
112 leveldb_options_destroy(c_options);
113
114 if error.is_null() {
115 Ok(Database::new(db, Some(comp_ptr)))
116 } else {
117 Err(Error::new_from_char(error))
118 }
119 }
120 }
121
122 pub fn put(
123 &self,
124 options: &WriteOptions,
125 key: &dyn IntoLevelDBKey,
126 value: &[u8],
127 ) -> Result<(), Error> {
128 key.as_u8_slice_for_write(&|k| self.put_u8(options, k, value))
129 }
130
131 pub fn put_u8(&self, options: &WriteOptions, key: &[u8], value: &[u8]) -> Result<(), Error> {
132 unsafe {
133 let mut error = ptr::null_mut();
134 let c_writeoptions = c_writeoptions(options);
135
136 leveldb_put(
137 self.database.ptr,
138 c_writeoptions,
139 key.as_ptr() as *mut c_char,
140 key.len() as size_t,
141 value.as_ptr() as *mut c_char,
142 value.len() as size_t,
143 &mut error,
144 );
145
146 leveldb_writeoptions_destroy(c_writeoptions);
147
148 if error.is_null() {
149 Ok(())
150 } else {
151 Err(Error::new_from_char(error))
152 }
153 }
154 }
155
156 pub fn get(
157 &self,
158 options: &ReadOptions,
159 key: &dyn IntoLevelDBKey,
160 ) -> Result<Option<Vec<u8>>, Error> {
161 key.as_u8_slice_for_get(&|k| self.get_u8(options, k))
162 }
163
164 pub fn get_u8(&self, options: &ReadOptions, key: &[u8]) -> Result<Option<Vec<u8>>, Error> {
165 unsafe {
166 let mut error = ptr::null_mut();
167 let mut length: size_t = 0;
168 let c_readoptions = c_readoptions(options);
169 let result = leveldb_get(
170 self.database.ptr,
171 c_readoptions,
172 key.as_ptr() as *mut c_char,
173 key.len() as size_t,
174 &mut length,
175 &mut error,
176 );
177 leveldb_readoptions_destroy(c_readoptions);
178
179 if error.is_null() {
180 let bytes_opt = Bytes::from_raw(result as *mut u8, length);
181
182 Ok(bytes_opt.map(|val| val.into()))
183 } else {
184 Err(Error::new_from_char(error))
185 }
186 }
187 }
188
189 pub fn delete(&self, options: &WriteOptions, key: &dyn IntoLevelDBKey) -> Result<(), Error> {
190 key.as_u8_slice_for_write(&|k| self.delete_u8(options, k))
191 }
192
193 pub fn delete_u8(&self, options: &WriteOptions, key: &[u8]) -> Result<(), Error> {
194 unsafe {
195 let mut error = ptr::null_mut();
196 let c_writeoptions = c_writeoptions(options);
197
198 leveldb_delete(
199 self.database.ptr,
200 c_writeoptions,
201 key.as_ptr() as *mut c_char,
202 key.len() as size_t,
203 &mut error,
204 );
205
206 leveldb_writeoptions_destroy(c_writeoptions);
207
208 if error.is_null() {
209 Ok(())
210 } else {
211 Err(Error::new_from_char(error))
212 }
213 }
214 }
215}
216
217pub trait DatabaseReader {
219 fn get(
220 &self,
221 options: &ReadOptions,
222 key: &dyn IntoLevelDBKey,
223 ) -> Result<Option<Vec<u8>>, Error>;
224
225 fn get_u8(
226 &self,
227 options: &ReadOptions,
228 key: &[u8],
229 ) -> Result<Option<Vec<u8>>, Error>;
230}
231
232impl DatabaseReader for Database {
233 fn get(
234 &self,
235 options: &ReadOptions,
236 key: &dyn IntoLevelDBKey,
237 ) -> Result<Option<Vec<u8>>, Error> {
238 self.get(options, key)
239 }
240
241 fn get_u8(
242 &self,
243 options: &ReadOptions,
244 key: &[u8],
245 ) -> Result<Option<Vec<u8>>, Error> {
246 self.get_u8(options, key)
247 }
248}