1#![crate_type = "lib"]
16#![warn(missing_docs)]
17#![warn(non_upper_case_globals)]
18#![warn(unused_qualifications)]
19
20extern crate libc;
21extern crate leveldb_sys;
22
23use std::cmp::Ordering;
24use std::ffi::{CStr,CString};
25use std::path::Path;
26use std::mem::transmute;
27use std::ptr;
28use std::slice;
29use std::sync::Arc;
30use std::str;
31
32use libc::{c_char, c_int, c_uchar, c_void, size_t};
33
34use leveldb_sys as cffi;
35
36
37#[derive(Clone, Hash, PartialEq, Eq, Debug)]
39pub enum LevelDBError {
40 LibraryError(String),
42
43 OutOfMemoryError,
45}
46
47impl std::fmt::Display for LevelDBError {
48 fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
49 match *self {
50 LevelDBError::LibraryError(ref msg) => msg.fmt(f),
51 LevelDBError::OutOfMemoryError => write!(f, "Out of memory"),
52 }
53 }
54}
55
56impl LevelDBError {
57 fn lib_error(errptr: *mut c_char) -> LevelDBError {
58 let p = errptr as *const c_char;
60 let slice = unsafe { CStr::from_ptr(p) };
61 let err = str::from_utf8(slice.to_bytes()).unwrap_or("Invalid error message").to_string();
62 unsafe { cffi::leveldb_free(errptr as *mut c_void) };
63
64 LevelDBError::LibraryError(err)
65 }
66}
67
68pub type LevelDBResult<T> = Result<T, LevelDBError>;
70
71fn with_errptr<F, T>(mut f: F) -> LevelDBResult<T>
74 where F: FnMut(*mut *mut c_char) -> T
75{
76 let mut errptr: *mut c_char = ptr::null_mut();
77
78 let ret = f(&mut errptr as *mut *mut c_char);
79
80 if !errptr.is_null() {
81 Err(LevelDBError::lib_error(errptr))
82 } else {
83 Ok(ret)
84 }
85}
86
87fn bool_to_uchar(val: bool) -> c_uchar {
88 if val {
89 1 as c_uchar
90 } else {
91 0 as c_uchar
92 }
93}
94
95fn uchar_to_bool(val: c_uchar) -> bool {
96 if val == 0 {
97 false
98 } else {
99 true
100 }
101}
102
103pub struct DBOptions {
108 opts: *mut cffi::leveldb_options_t,
109
110 comparator: Option<DBComparator>,
113}
114
115impl DBOptions {
116 pub fn new() -> Option<DBOptions> {
121 let opts = unsafe { cffi::leveldb_options_create() };
122 if opts.is_null() {
123 None
124 } else {
125 Some(DBOptions {
126 opts: opts,
127 comparator: None,
128 })
129 }
130 }
131
132 pub fn set_comparator(&mut self, cmp: DBComparator) -> &mut DBOptions {
138 unsafe {
139 cffi::leveldb_options_set_comparator(self.opts, cmp.state.ptr);
140 }
141
142 self.comparator = Some(cmp);
145
146 self
147 }
148
149 pub fn set_create_if_missing(&mut self, val: bool) -> &mut DBOptions {
155 unsafe {
156 cffi::leveldb_options_set_create_if_missing(self.opts, bool_to_uchar(val));
157 }
158
159 self
160 }
161
162 pub fn set_error_if_exists(&mut self, val: bool) -> &mut DBOptions {
168 unsafe {
169 cffi::leveldb_options_set_error_if_exists(self.opts, bool_to_uchar(val));
170 }
171
172 self
173 }
174
175 pub fn set_paranoid_checks(&mut self, val: bool) -> &mut DBOptions {
182 unsafe {
183 cffi::leveldb_options_set_paranoid_checks(self.opts, bool_to_uchar(val));
184 }
185
186 self
187 }
188
189 pub fn set_write_buffer_size(&mut self, val: usize) -> &mut DBOptions {
196 unsafe {
197 cffi::leveldb_options_set_write_buffer_size(self.opts, val as size_t);
198 }
199
200 self
201 }
202
203 pub fn set_max_open_files(&mut self, val: isize) -> &mut DBOptions {
210 unsafe {
211 cffi::leveldb_options_set_max_open_files(self.opts, val as c_int);
212 }
213
214 self
215 }
216
217 pub fn set_block_size(&mut self, val: usize) -> &mut DBOptions {
224 unsafe {
225 cffi::leveldb_options_set_block_size(self.opts, val as size_t);
226 }
227
228 self
229 }
230
231 pub fn set_block_restart_interval(&mut self, val: isize) -> &mut DBOptions {
238 unsafe {
239 cffi::leveldb_options_set_block_restart_interval(self.opts, val as c_int);
240 }
241
242 self
243 }
244
245 #[cfg(feature = "snappy")]
253 pub fn set_compression(&mut self, val: bool) -> &mut DBOptions {
254 let val = if val {
255 cffi::Compression::Snappy
256 } else {
257 cffi::Compression::No
258 };
259
260 unsafe {
261 cffi::leveldb_options_set_compression(self.opts, val);
262 }
263
264 self
265 }
266
267 unsafe fn ptr(&self) -> *const cffi::leveldb_options_t {
268 self.opts as *const cffi::leveldb_options_t
269 }
270}
271
272impl Drop for DBOptions {
273 fn drop(&mut self) {
274 unsafe { cffi::leveldb_options_destroy(self.opts) };
275 }
276}
277
278struct DBComparatorState {
285 name: &'static str,
286 cmp: Box<Fn(&[u8], &[u8]) -> Ordering + 'static>,
287 ptr: *mut cffi::leveldb_comparator_t,
288}
289
290impl Drop for DBComparatorState {
291 fn drop(&mut self) {
292 unsafe { cffi::leveldb_comparator_destroy(self.ptr) };
293 }
294}
295
296pub struct DBComparator {
300 state: Box<DBComparatorState>,
301}
302
303impl DBComparator {
304 pub fn new<F: 'static>(name: &'static str, cmp: F) -> DBComparator
308 where F: Fn(&[u8], &[u8]) -> Ordering
309 {
310 let mut state = Box::new(DBComparatorState {
311 name: name,
312 cmp: Box::new(cmp),
313 ptr: ptr::null_mut(),
314 });
315
316 let ptr = unsafe {
317 cffi::leveldb_comparator_create(
318 transmute(&*state),
319 comparator_destructor_callback,
320 comparator_compare_callback,
321 comparator_name_callback,
322 )
323 };
324
325 state.ptr = ptr;
326
327 DBComparator {
328 state: state,
329 }
330 }
331}
332
333#[allow(dead_code)]
334extern "C" fn comparator_destructor_callback(_state: *mut c_void) {
335 }
337
338#[allow(dead_code)]
339extern "C" fn comparator_compare_callback(state: *mut c_void, a: *const c_char, alen: size_t, b: *const c_char, blen: size_t) -> c_int {
340 unsafe {
341 let cmp: *const DBComparatorState = transmute(state);
343
344 let a_slice = slice::from_raw_parts::<u8>(a as *const u8, alen as usize);
345 let b_slice = slice::from_raw_parts::<u8>(b as *const u8, blen as usize);
346
347 match ((*cmp).cmp)(a_slice, b_slice) {
353 Ordering::Less => -1,
354 Ordering::Equal => 0,
355 Ordering::Greater => 1,
356 }
357 }
358}
359
360#[allow(dead_code)]
361extern "C" fn comparator_name_callback(state: *mut c_void) -> *const c_char {
362 unsafe {
363 let cmp: *const DBComparatorState = transmute(state);
365
366 (*cmp).name.as_ptr() as *const c_char
368 }
369}
370
371pub struct DBReadOptions {
376 opts: *mut cffi::leveldb_readoptions_t,
377}
378
379impl DBReadOptions {
380 pub fn new() -> Option<DBReadOptions> {
385 let opts = unsafe { cffi::leveldb_readoptions_create() };
386 if opts.is_null() {
387 None
388 } else {
389 Some(DBReadOptions {
390 opts: opts,
391 })
392 }
393 }
394
395 pub fn set_verify_checksums(&mut self, val: bool) -> &mut DBReadOptions {
402 unsafe {
403 cffi::leveldb_readoptions_set_verify_checksums(self.opts, bool_to_uchar(val));
404 }
405
406 self
407 }
408
409 pub fn set_fill_cache(&mut self, val: bool) -> &mut DBReadOptions {
415 unsafe {
416 cffi::leveldb_readoptions_set_fill_cache(self.opts, bool_to_uchar(val));
417 }
418
419 self
420 }
421
422 fn set_snapshot(&mut self, snap: *const cffi::leveldb_snapshot_t) -> &mut DBReadOptions {
431 unsafe {
432 cffi::leveldb_readoptions_set_snapshot(self.opts, snap);
433 }
434
435 self
436 }
437
438 unsafe fn ptr(&self) -> *const cffi::leveldb_readoptions_t {
439 self.opts as *const cffi::leveldb_readoptions_t
440 }
441}
442
443impl Drop for DBReadOptions {
444 fn drop(&mut self) {
445 unsafe { cffi::leveldb_readoptions_destroy(self.opts) };
446 }
447}
448
449pub struct DBWriteOptions {
454 opts: *mut cffi::leveldb_writeoptions_t,
455}
456
457impl DBWriteOptions {
458 pub fn new() -> Option<DBWriteOptions> {
463 let opts = unsafe { cffi::leveldb_writeoptions_create() };
464 if opts.is_null() {
465 None
466 } else {
467 Some(DBWriteOptions {
468 opts: opts,
469 })
470 }
471 }
472
473 pub fn set_sync(&mut self, val: bool) -> &mut DBWriteOptions {
483 unsafe {
484 cffi::leveldb_writeoptions_set_sync(self.opts, bool_to_uchar(val));
485 }
486
487 self
488 }
489
490 unsafe fn ptr(&self) -> *const cffi::leveldb_writeoptions_t {
491 self.opts as *const cffi::leveldb_writeoptions_t
492 }
493}
494
495impl Drop for DBWriteOptions {
496 fn drop(&mut self) {
497 unsafe { cffi::leveldb_writeoptions_destroy(self.opts) };
498 }
499}
500
501pub struct DBWriteBatch {
507 batch: *mut cffi::leveldb_writebatch_t,
508}
509
510impl DBWriteBatch {
511 pub fn new() -> Option<DBWriteBatch> {
516 let batch = unsafe { cffi::leveldb_writebatch_create() };
517 if batch.is_null() {
518 None
519 } else {
520 Some(DBWriteBatch {
521 batch: batch,
522 })
523 }
524 }
525
526 pub fn put(&mut self, key: &[u8], val: &[u8]) {
531 unsafe {
534 cffi::leveldb_writebatch_put(
535 self.batch,
536 key.as_ptr() as *const c_char,
537 key.len() as size_t,
538 val.as_ptr() as *const c_char,
539 val.len() as size_t
540 )
541 }
542 }
543
544 pub fn clear(&mut self) {
548 unsafe { cffi::leveldb_writebatch_clear(self.batch) };
549 }
550
551 pub fn delete(&mut self, key: &[u8]) {
556 unsafe {
557 cffi::leveldb_writebatch_delete(
558 self.batch,
559 key.as_ptr() as *const c_char,
560 key.len() as size_t
561 )
562 };
563 }
564
565 pub fn iterate<'a, F: 'a, G: 'a>(&'a self, put: F, delete: G)
570 where F: FnMut(&'a [u8], &'a [u8]) + 'a,
571 G: FnMut(&'a [u8]) + 'a,
572 {
573 let mut it = DBWriteBatchIter {
574 put: Box::new(put),
575 delete: Box::new(delete),
576 };
577
578 unsafe {
579 cffi::leveldb_writebatch_iterate(
580 self.batch,
581 &mut it as *mut _ as *mut c_void,
582 writebatch_put_callback,
583 writebatch_delete_callback
584 );
585 };
586 }
587}
588
589struct DBWriteBatchIter<'a> {
590 pub put: Box<FnMut(&'a [u8], &'a [u8]) + 'a>,
591 pub delete: Box<FnMut(&'a [u8]) + 'a>,
592}
593
594extern "C" fn writebatch_put_callback(state: *mut c_void, key: *const c_char, klen: size_t, val: *const c_char, vlen: size_t) {
596 let it = state as *mut DBWriteBatchIter;
597
598 let key_slice = unsafe {
599 slice::from_raw_parts::<u8>(key as *const u8, klen as usize)
600 };
601 let val_slice = unsafe {
602 slice::from_raw_parts::<u8>(val as *const u8, vlen as usize)
603 };
604
605 unsafe { ((*it).put)(key_slice, val_slice) };
606}
607
608extern "C" fn writebatch_delete_callback(state: *mut c_void, key: *const c_char, klen: size_t) {
610 let it = state as *mut DBWriteBatchIter;
611
612 let key_slice = unsafe {
613 slice::from_raw_parts::<u8>(key as *const u8, klen as usize)
614 };
615
616 unsafe { ((*it).delete)(key_slice) };
617}
618
619impl Drop for DBWriteBatch {
620 fn drop(&mut self) {
621 unsafe { cffi::leveldb_writebatch_destroy(self.batch) };
622 }
623}
624
625pub struct DBIterator {
631 iter: *mut cffi::leveldb_iterator_t,
632}
633
634impl DBIterator {
635 fn new(i: *mut cffi::leveldb_iterator_t) -> DBIterator {
637 unsafe { cffi::leveldb_iter_seek_to_first(i) };
638
639 DBIterator {
640 iter: i,
641 }
642 }
643
644 pub fn next<'a>(&'a mut self) -> Option<(&'a [u8], &'a [u8])> {
648 if !uchar_to_bool(unsafe { cffi::leveldb_iter_valid(self.ptr()) }) {
649 return None;
650 }
651
652 let key_slice = unsafe {
653 let mut keylen: size_t = 0;
654 let key = cffi::leveldb_iter_key(self.ptr(),
655 &mut keylen as *mut size_t);
656
657 slice::from_raw_parts::<u8>(key as *const u8, keylen as usize)
658 };
659
660 let val_slice = unsafe {
661 let mut vallen: size_t = 0;
662 let val = cffi::leveldb_iter_value(
663 self.ptr(), &mut vallen as *mut size_t);
664
665 slice::from_raw_parts::<u8>(val as *const u8, vallen as usize)
666 };
667
668 unsafe { cffi::leveldb_iter_next(self.iter) };
669
670 Some((key_slice, val_slice))
671 }
672
673 pub fn alloc(self) -> DBIteratorAlloc {
679 DBIteratorAlloc::new(self)
680 }
681
682 pub fn seek_to_first(&mut self) {
686 unsafe { cffi::leveldb_iter_seek_to_first(self.iter) };
687 }
688
689 pub fn seek_to_last(&mut self) {
693 unsafe { cffi::leveldb_iter_seek_to_last(self.iter) };
694 }
695
696 pub fn seek(&mut self, key: &[u8]) {
701 unsafe {
702 cffi::leveldb_iter_seek(
703 self.iter,
704 key.as_ptr() as *const c_char,
705 key.len() as size_t
706 );
707 }
708 }
709
710 pub fn prev(&mut self) {
714 unsafe { cffi::leveldb_iter_prev(self.iter) };
715 }
716
717 fn ptr(&self) -> *const cffi::leveldb_iterator_t {
718 self.iter as *const cffi::leveldb_iterator_t
719 }
720}
721
722impl Drop for DBIterator {
723 fn drop(&mut self) {
724 unsafe { cffi::leveldb_iter_destroy(self.iter) };
725 }
726}
727
728pub struct DBIteratorAlloc {
733 underlying: DBIterator,
734}
735
736impl DBIteratorAlloc {
737 fn new(i: DBIterator) -> DBIteratorAlloc {
739 DBIteratorAlloc {
740 underlying: i,
741 }
742 }
743
744 pub fn seek_to_first(&mut self) {
748 self.underlying.seek_to_first()
749 }
750
751 pub fn seek_to_last(&mut self) {
755 self.underlying.seek_to_last()
756 }
757
758 pub fn seek(&mut self, key: &[u8]) {
762 self.underlying.seek(key)
763 }
764}
765
766impl Iterator for DBIteratorAlloc {
767 type Item = (Vec<u8>, Vec<u8>);
768
769 fn next(&mut self) -> Option<(Vec<u8>, Vec<u8>)> {
770 match self.underlying.next() {
771 Some((key, val)) => {
772 Some((key.to_vec(), val.to_vec()))
773 },
774 None => None,
775 }
776 }
777}
778
779pub struct DBSnapshot {
783 sn: *mut cffi::leveldb_snapshot_t,
784
785 db: DBImplPtr,
788}
789
790impl DBSnapshot {
791 fn new_from(db: &DBImplPtr) -> DBSnapshot {
793 let db = db.clone();
795
796 let sn = unsafe { cffi::leveldb_create_snapshot(db.db) };
797
798 DBSnapshot {
799 sn: sn,
800 db: db,
801 }
802 }
803
804 pub fn get(&self, key: &[u8]) -> LevelDBResult<Option<Vec<u8>>> {
808 let opts = match DBReadOptions::new() {
810 Some(o) => o,
811 None => return Err(LevelDBError::OutOfMemoryError),
812 };
813
814 self.get_opts(key, opts)
815 }
816
817 pub fn get_opts(&self, key: &[u8], opts: DBReadOptions) -> LevelDBResult<Option<Vec<u8>>> {
821 let mut opts = opts;
822
823 opts.set_snapshot(self.sn as *const cffi::leveldb_snapshot_t);
824 self.db.get(key, opts)
825 }
826
827 pub fn iter(&self) -> LevelDBResult<DBIterator> {
831 let mut opts = match DBReadOptions::new() {
833 Some(o) => o,
834 None => return Err(LevelDBError::OutOfMemoryError),
835 };
836
837 opts.set_snapshot(self.sn as *const cffi::leveldb_snapshot_t);
838 Ok(self.db.iter(opts))
839 }
840
841}
842
843impl Drop for DBSnapshot {
844 fn drop(&mut self) {
845 unsafe {
846 cffi::leveldb_release_snapshot(
847 self.db.db,
848 self.sn as *const cffi::leveldb_snapshot_t,
849 )
850 };
851 }
852}
853
854struct DBImpl {
866 db: *mut cffi::leveldb_t,
868
869 #[allow(dead_code)]
872 opts: DBOptions,
873}
874
875impl DBImpl {
876 fn open(path: &Path, opts: DBOptions) -> LevelDBResult<DBImplPtr> {
877 let res = with_errptr(|errptr| {
878 let c_string = CString::new(path.to_str().unwrap()).unwrap();
879 unsafe { cffi::leveldb_open(opts.ptr(), c_string.as_ptr(), errptr) }
880 });
881
882 let db = match res {
883 Ok(db) => db,
884 Err(v) => return Err(v),
885 };
886
887 Ok(Arc::new(DBImpl {
888 db: db,
889 opts: opts,
890 }))
891 }
892
893 fn put(&self, key: &[u8], val: &[u8], opts: DBWriteOptions) -> LevelDBResult<()> {
894 try!(with_errptr(|errptr| {
895 unsafe {
896 cffi::leveldb_put(
897 self.db,
898 opts.ptr(),
899 key.as_ptr() as *const c_char,
900 key.len() as size_t,
901 val.as_ptr() as *const c_char,
902 val.len() as size_t,
903 errptr
904 )
905 }
906 }));
907
908 Ok(())
909 }
910
911 fn delete(&self, key: &[u8], opts: DBWriteOptions) -> LevelDBResult<()> {
912 try!(with_errptr(|errptr| {
913 unsafe {
914 cffi::leveldb_delete(
915 self.db,
916 opts.ptr(),
917 key.as_ptr() as *const c_char,
918 key.len() as size_t,
919 errptr
920 )
921 }
922 }));
923
924 Ok(())
925 }
926
927 fn write(&self, batch: DBWriteBatch, opts: DBWriteOptions) -> LevelDBResult<()> {
928 try!(with_errptr(|errptr| {
929 unsafe {
930 cffi::leveldb_write(
931 self.db,
932 opts.ptr(),
933 batch.batch,
934 errptr
935 )
936 }
937 }));
938
939 Ok(())
940 }
941
942 fn get(&self, key: &[u8], opts: DBReadOptions) -> LevelDBResult<Option<Vec<u8>>> {
943 let mut size: size_t = 0;
944
945 let buff = try!(with_errptr(|errptr| {
946 unsafe {
947 cffi::leveldb_get(
948 self.db,
949 opts.ptr(),
950 key.as_ptr() as *const c_char,
951 key.len() as size_t,
952 &mut size as *mut size_t,
953 errptr
954 )
955 }
956 }));
957
958 if buff.is_null() {
959 return Ok(None)
960 }
961
962 let size = size as usize;
963
964 let vec: Vec<u8> = unsafe { slice::from_raw_parts(buff as *mut u8, size).to_vec() };
965
966 Ok(Some(vec))
967 }
968
969 fn iter(&self, opts: DBReadOptions) -> DBIterator {
970 let it = unsafe {
971 cffi::leveldb_create_iterator(
972 self.db,
973 opts.ptr()
974 )
975 };
976
977 DBIterator::new(it)
978 }
979}
980
981impl Drop for DBImpl {
982 fn drop(&mut self) {
983 unsafe {
984 cffi::leveldb_close(self.db)
985 }
986 }
987}
988
989type DBImplPtr = Arc<DBImpl>;
992
993#[derive(Clone)]
997pub struct DB {
998 db: DBImplPtr,
999}
1000
1001unsafe impl Send for DB {}
1002unsafe impl Sync for DB {}
1003
1004impl DB {
1005 pub fn open(path: &Path) -> LevelDBResult<DB> {
1011 let opts = match DBOptions::new() {
1013 Some(o) => o,
1014 None => return Err(LevelDBError::OutOfMemoryError),
1015 };
1016
1017 DB::open_with_opts(path, opts)
1018 }
1019
1020 pub fn create(path: &Path) -> LevelDBResult<DB> {
1024 let mut opts = match DBOptions::new() {
1026 Some(o) => o,
1027 None => return Err(LevelDBError::OutOfMemoryError),
1028 };
1029
1030 opts.set_create_if_missing(true);
1033 DB::open_with_opts(path, opts)
1034 }
1035
1036 pub fn open_with_opts(path: &Path, opts: DBOptions) -> LevelDBResult<DB> {
1042 match DBImpl::open(path, opts) {
1043 Ok(x) => Ok(DB { db: x }),
1044 Err(why) => Err(why),
1045 }
1046 }
1047
1048 pub fn put(&mut self, key: &[u8], val: &[u8]) -> LevelDBResult<()> {
1053 let opts = match DBWriteOptions::new() {
1055 Some(o) => o,
1056 None => return Err(LevelDBError::OutOfMemoryError),
1057 };
1058
1059 self.put_opts(key, val, opts)
1060 }
1061
1062 pub fn put_opts(&mut self, key: &[u8], val: &[u8], opts: DBWriteOptions) -> LevelDBResult<()> {
1067 self.db.put(key, val, opts)
1068 }
1069
1070 pub fn delete(&mut self, key: &[u8]) -> LevelDBResult<()> {
1076 let opts = match DBWriteOptions::new() {
1078 Some(o) => o,
1079 None => return Err(LevelDBError::OutOfMemoryError),
1080 };
1081
1082 self.delete_opts(key, opts)
1083 }
1084
1085 pub fn delete_opts(&mut self, key: &[u8], opts: DBWriteOptions) -> LevelDBResult<()> {
1090 self.db.delete(key, opts)
1091 }
1092
1093 pub fn write(&mut self, batch: DBWriteBatch) -> LevelDBResult<()> {
1098 let opts = match DBWriteOptions::new() {
1100 Some(o) => o,
1101 None => return Err(LevelDBError::OutOfMemoryError),
1102 };
1103
1104 self.write_opts(batch, opts)
1105 }
1106
1107 pub fn write_opts(&mut self, batch: DBWriteBatch, opts: DBWriteOptions) -> LevelDBResult<()> {
1112 self.db.write(batch, opts)
1113 }
1114
1115 pub fn get(&self, key: &[u8]) -> LevelDBResult<Option<Vec<u8>>> {
1121 let opts = match DBReadOptions::new() {
1123 Some(o) => o,
1124 None => return Err(LevelDBError::OutOfMemoryError),
1125 };
1126
1127 self.get_opts(key, opts)
1128 }
1129
1130 pub fn get_opts(&self, key: &[u8], opts: DBReadOptions) -> LevelDBResult<Option<Vec<u8>>> {
1135 self.db.get(key, opts)
1136 }
1137
1138 pub fn iter(&mut self) -> LevelDBResult<DBIterator> {
1142 let opts = match DBReadOptions::new() {
1144 Some(o) => o,
1145 None => return Err(LevelDBError::OutOfMemoryError),
1146 };
1147
1148 Ok(self.db.iter(opts))
1149 }
1150
1151 pub fn snapshot(&self) -> DBSnapshot {
1155 DBSnapshot::new_from(&self.db)
1156 }
1157
1158 }
1166
1167#[cfg(test)]
1168mod tests {
1169 #![allow(unused_imports)]
1170
1171 extern crate tempdir;
1172
1173 use self::tempdir::TempDir;
1174 use leveldb_sys as ffi;
1175
1176 use super::{DB, DBComparator, DBOptions, DBReadOptions, DBWriteBatch};
1177
1178 fn new_temp_db(name: &str) -> DB {
1179 let tdir = match TempDir::new(name) {
1180 Ok(t) => t,
1181 Err(why) => panic!("Error creating temp dir: {:?}", why),
1182 };
1183
1184 match DB::create(tdir.path()) {
1185 Ok(db) => db,
1186 Err(why) => panic!("Error creating DB: {:?}", why),
1187 }
1188 }
1189
1190 #[test]
1191 fn test_can_get_version() {
1192 let major_ver = unsafe { ffi::leveldb_major_version() };
1193 let minor_ver = unsafe { ffi::leveldb_minor_version() };
1194
1195 assert!(major_ver >= 1);
1196 assert!(minor_ver >= 0);
1197 }
1198
1199 #[test]
1200 fn test_can_create() {
1201 let tdir = match TempDir::new("create") {
1202 Ok(t) => t,
1203 Err(why) => panic!("Error creating temp dir: {:?}", why),
1204 };
1205
1206 let _db = match DB::create(tdir.path()) {
1207 Ok(db) => db,
1208 Err(why) => panic!("Error creating DB: {:?}", why),
1209 };
1210 }
1211
1212 #[test]
1213 fn test_put() {
1214 let mut db = new_temp_db("put");
1215
1216 match db.put(b"foo", b"bar") {
1217 Ok(_) => {},
1218 Err(why) => panic!("Error putting into DB: {:?}", why),
1219 };
1220 }
1221
1222 #[test]
1223 fn test_put_and_get() {
1224 let mut db = new_temp_db("put-and-get");
1225
1226 match db.put(b"foo", b"bar") {
1227 Ok(_) => {},
1228 Err(why) => panic!("Error putting into DB: {:?}", why),
1229 };
1230
1231 match db.get(b"foo") {
1232 Ok(v) => assert_eq!(v.expect("Value not found"), b"bar"),
1233 Err(why) => panic!("Error getting from DB: {:?}", why),
1234 };
1235 }
1236
1237 #[test]
1238 fn test_delete() {
1239 let mut db = new_temp_db("delete");
1240
1241 db.put(b"foo", b"bar").unwrap();
1242 db.put(b"abc", b"123").unwrap();
1243
1244 assert_eq!(db.get(b"foo").unwrap().expect("Value not found"), b"bar");
1246 assert_eq!(db.get(b"abc").unwrap().expect("Value not found"), b"123");
1247
1248 match db.delete(b"foo") {
1249 Ok(_) => {},
1250 Err(why) => panic!("Error deleting from DB: {:?}", why),
1251 }
1252
1253 assert_eq!(db.get(b"foo").unwrap(), None);
1254 assert_eq!(db.get(b"abc").unwrap().expect("Value not found"), b"123");
1255 }
1256
1257 #[test]
1258 fn test_write_batch() {
1259 let mut db = new_temp_db("write-batch");
1260
1261 db.put(b"foo", b"bar").unwrap();
1262 db.put(b"abc", b"123").unwrap();
1263
1264 let mut batch = DBWriteBatch::new().expect("Error creating batch");
1267
1268 batch.put(b"def", b"456");
1269 batch.put(b"zzz", b"asdfgh");
1270 batch.delete(b"abc");
1271 batch.put(b"zzz", b"qwerty");
1272
1273 let mut puts: Vec<(Vec<u8>, Vec<u8>)> = vec![];
1276 let mut deletes: Vec<Vec<u8>> = vec![];
1277
1278 batch.iterate(|k, v| {
1279 puts.push((k.to_vec(), v.to_vec()));
1280 }, |k| {
1281 deletes.push(k.to_vec());
1282 });
1283
1284 assert_eq!(puts.len(), 3);
1285 assert_eq!(deletes.len(), 1);
1286
1287 match db.write(batch) {
1290 Ok(_) => {},
1291 Err(why) => panic!("Error writing to DB: {:?}", why),
1292 };
1293
1294 assert_eq!(db.get(b"foo").unwrap().expect("Value not found"), b"bar");
1295 assert_eq!(db.get(b"def").unwrap().expect("Value not found"), b"456");
1296 assert_eq!(db.get(b"zzz").unwrap().expect("Value not found"), b"qwerty");
1297 }
1298
1299 #[test]
1300 fn test_iteration() {
1301 let mut db = new_temp_db("iteration");
1302
1303 db.put(b"foo", b"bar").unwrap();
1304 db.put(b"abc", b"123").unwrap();
1305
1306 let mut it = db.iter().unwrap();
1307
1308 let t1 = match it.next() {
1309 Some((key, val)) => {
1310 (key.to_vec(), val.to_vec())
1311 },
1312 None => panic!("Expected item 1"),
1313 };
1314 let t2 = match it.next() {
1315 Some((key, val)) => {
1316 (key.to_vec(), val.to_vec())
1317 },
1318 None => panic!("Expected item 2"),
1319 };
1320 let t3 = it.next();
1321
1322 assert_eq!((&t1.0), b"abc");
1324 assert_eq!((&t1.1), b"123");
1325
1326 assert_eq!((&t2.0), b"foo");
1327 assert_eq!((&t2.1), b"bar");
1328
1329 assert!(t3.is_none());
1330 }
1331
1332 #[test]
1333 fn test_iteration_alloc() {
1334 let mut db = new_temp_db("iteration");
1335
1336 db.put(b"foo", b"bar").unwrap();
1337 db.put(b"abc", b"123").unwrap();
1338
1339 let items: Vec<(Vec<u8>, Vec<u8>)> = db.iter().unwrap().alloc().collect();
1340
1341 assert_eq!(items.len(), 2);
1342 assert_eq!((&items[0].0), b"abc");
1343 assert_eq!((&items[0].1), b"123");
1344 assert_eq!((&items[1].0), b"foo");
1345 assert_eq!((&items[1].1), b"bar");
1346 }
1347
1348 #[test]
1349 fn test_comparator_create() {
1350 let _c = DBComparator::new("comparator-create", |a, b| {
1351 a.cmp(b)
1352 });
1353 }
1354
1355 #[test]
1356 fn test_comparator() {
1357 let c = DBComparator::new("foo", |a, b| {
1358 b.cmp(a)
1360 });
1361
1362 let mut opts = DBOptions::new().expect("error creating options");
1363 opts.set_comparator(c).set_create_if_missing(true);
1364
1365 let tdir = match TempDir::new("comparator") {
1366 Ok(t) => t,
1367 Err(why) => panic!("Error creating temp dir: {:?}", why),
1368 };
1369
1370 let mut db = match DB::open_with_opts(tdir.path(), opts) {
1371 Ok(db) => db,
1372 Err(why) => panic!("Error creating DB: {:?}", why),
1373 };
1374
1375 db.put(b"aaaa", b"foo").unwrap();
1377 db.put(b"zzzz", b"bar").unwrap();
1378
1379 let items: Vec<(Vec<u8>, Vec<u8>)> = db.iter().unwrap().alloc().collect();
1381
1382 assert_eq!(items.len(), 2);
1384 assert_eq!((&items[0].0), b"zzzz");
1385 assert_eq!((&items[0].1), b"bar");
1386 assert_eq!((&items[1].0), b"aaaa");
1387 assert_eq!((&items[1].1), b"foo");
1388 }
1389
1390 #[test]
1391 fn test_snapshot() {
1392 let mut db = new_temp_db("snapshot");
1393
1394 db.put(b"foo", b"bar").unwrap();
1395 db.put(b"abc", b"123").unwrap();
1396
1397 let snap = db.snapshot();
1398
1399 db.put(b"abc", b"456").unwrap();
1400
1401 let snap_val = match snap.get(b"abc") {
1402 Ok(val) => val.expect("Expected to find key 'abc'"),
1403 Err(why) => panic!("Error getting from DB: {:?}", why),
1404 };
1405 assert_eq!(snap_val, b"123");
1406
1407 let val = match db.get(b"abc") {
1408 Ok(val) => val.expect("Expected to find key 'abc'"),
1409 Err(why) => panic!("Error getting from DB: {:?}", why),
1410 };
1411 assert!(val == b"456");
1412
1413 let iter_items: Vec<(Vec<u8>, Vec<u8>)> = snap.iter().unwrap().alloc().collect();
1414 let db_items: Vec<(Vec<u8>, Vec<u8>)> = db.iter().unwrap().alloc().collect();
1415
1416 assert_eq!(iter_items.len(), 2);
1417 assert_eq!(db_items.len(), 2);
1418
1419 assert_eq!((&iter_items[0].0), b"abc");
1420 assert_eq!((&iter_items[0].1), b"123");
1421 assert_eq!((&iter_items[1].0), b"foo");
1422 assert_eq!((&iter_items[1].1), b"bar");
1423
1424 assert_eq!((&db_items[0].0), b"abc");
1425 assert_eq!((&db_items[0].1), b"456");
1426 assert_eq!((&db_items[1].0), b"foo");
1427 assert_eq!((&db_items[1].1), b"bar");
1428 }
1429}