use super::Database;
use super::error::Error;
use super::slice::Slice;
use crate::binding::*;
use crate::options::{WriteOptions, c_writeoptions};
use libc::{c_char, c_void, size_t};
use std::ptr;
use std::slice;
#[allow(missing_docs)]
pub struct Writebatch {
ptr: *mut leveldb_writebatch_t,
}
impl Drop for Writebatch {
fn drop(&mut self) {
unsafe {
leveldb_writebatch_destroy(self.ptr);
}
}
}
pub trait Batch {
fn write(&self, options: WriteOptions, batch: &Writebatch) -> Result<(), Error>;
}
impl Batch for Database {
fn write(&self, options: WriteOptions, batch: &Writebatch) -> Result<(), Error> {
unsafe {
let mut error = ptr::null_mut();
let c_writeoptions = c_writeoptions(options);
leveldb_write(self.database.ptr, c_writeoptions, batch.ptr, &mut error);
leveldb_writeoptions_destroy(c_writeoptions);
if error.is_null() {
Ok(())
} else {
Err(Error::new_from_char(error))
}
}
}
}
impl Default for Writebatch {
fn default() -> Self {
Self::new()
}
}
impl Writebatch {
pub fn new() -> Writebatch {
let ptr = unsafe { leveldb_writebatch_create() };
Writebatch { ptr }
}
pub fn clear(&mut self) {
unsafe { leveldb_writebatch_clear(self.ptr) };
}
pub fn put(&mut self, key: Slice, value: Slice) {
unsafe {
let key_bytes = key.as_bytes();
let value_bytes = value.as_bytes();
leveldb_writebatch_put(
self.ptr,
(key_bytes.as_ptr()) as *mut c_char,
(key_bytes.len()) as size_t,
value_bytes.as_ptr() as *mut c_char,
value_bytes.len() as size_t,
);
}
}
pub fn delete(&mut self, key: Slice) {
unsafe {
let key_bytes = key.as_bytes();
leveldb_writebatch_delete(
self.ptr,
key_bytes.as_ptr() as *mut c_char,
key_bytes.len() as size_t,
);
}
}
pub fn iterate<T: WritebatchIterator>(&mut self, iterator: Box<T>) -> Box<T> {
unsafe {
let iter = Box::into_raw(iterator);
leveldb_writebatch_iterate(
self.ptr,
iter as *mut c_void,
put_callback::<T>,
deleted_callback::<T>,
);
Box::from_raw(iter)
}
}
}
pub trait WritebatchIterator {
fn put(&mut self, key: Slice, value: Slice);
fn deleted(&mut self, key: Slice);
}
extern "C" fn put_callback<T: WritebatchIterator>(
state: *mut c_void,
key: *const c_char,
keylen: size_t,
val: *const c_char,
vallen: size_t,
) {
unsafe {
let iter: &mut T = &mut *(state as *mut T);
let key_slice = slice::from_raw_parts::<u8>(key as *const u8, keylen);
let val_slice = slice::from_raw_parts::<u8>(val as *const u8, vallen);
iter.put(Slice::from(key_slice), Slice::from(val_slice));
}
}
extern "C" fn deleted_callback<T: WritebatchIterator>(
state: *mut c_void,
key: *const c_char,
keylen: size_t,
) {
unsafe {
let iter: &mut T = &mut *(state as *mut T);
let key_slice = slice::from_raw_parts::<u8>(key as *const u8, keylen);
iter.deleted(Slice::from(key_slice));
}
}