use crate::binding::{
leveldb_filterpolicy_create, leveldb_filterpolicy_create_bloom, leveldb_filterpolicy_destroy,
leveldb_filterpolicy_t,
};
use libc::{c_char, c_uchar, c_void};
use std::ffi::CString;
use std::os::raw::c_int;
use std::slice;
pub trait LevelDBFilterPolicy {
fn raw_ptr(&self) -> *mut leveldb_filterpolicy_t;
}
pub struct BloomFilterPolicy {
ptr: *mut leveldb_filterpolicy_t,
}
impl BloomFilterPolicy {
pub fn new(bits_per_key: i32) -> BloomFilterPolicy {
let ptr = unsafe { leveldb_filterpolicy_create_bloom(bits_per_key) };
BloomFilterPolicy { ptr }
}
}
impl LevelDBFilterPolicy for BloomFilterPolicy {
fn raw_ptr(&self) -> *mut leveldb_filterpolicy_t {
self.ptr
}
}
impl Drop for BloomFilterPolicy {
fn drop(&mut self) {
unsafe {
leveldb_filterpolicy_destroy(self.ptr);
}
}
}
pub trait FilterPolicy {
fn create_filter(&self, keys: &[&[u8]]) -> Vec<u8>;
fn key_may_match(&self, key: &[u8], filter: &[u8]) -> bool;
fn name(&self) -> &'static str;
}
pub struct CustomFilterPolicy<T: FilterPolicy> {
ptr: *mut leveldb_filterpolicy_t,
policy: T,
}
impl<T: FilterPolicy> CustomFilterPolicy<T> {
pub fn new(policy: T) -> Self {
let boxed_policy = Box::new(policy);
let state = Box::into_raw(boxed_policy) as *mut c_void;
extern "C" fn destructor<T: FilterPolicy>(state: *mut c_void) {
unsafe {
let _ = Box::from_raw(state as *mut T);
}
}
extern "C" fn create_filter<T: FilterPolicy>(
state: *mut c_void,
key_array: *const *const c_char,
key_length_array: *const usize,
num_keys: c_int,
filter_length: *mut usize,
) -> *mut c_char {
unsafe {
let policy = &*(state as *const T);
let keys: Vec<&[u8]> = (0..num_keys as usize)
.map(|i| {
let key_ptr = *key_array.add(i);
let key_len = *key_length_array.add(i);
slice::from_raw_parts(key_ptr as *const u8, key_len)
})
.collect();
let filter_data = policy.create_filter(&keys);
*filter_length = filter_data.len();
let mut boxed_filter = filter_data.into_boxed_slice();
let ptr = boxed_filter.as_mut_ptr() as *mut c_char;
let _ = Box::into_raw(boxed_filter);
ptr
}
}
extern "C" fn key_may_match<T: FilterPolicy>(
state: *mut c_void,
key: *const c_char,
key_length: usize,
filter: *const c_char,
filter_length: usize,
) -> c_uchar {
unsafe {
let policy = &*(state as *const T);
let key_slice = slice::from_raw_parts(key as *const u8, key_length);
let filter_slice = slice::from_raw_parts(filter as *const u8, filter_length);
policy.key_may_match(key_slice, filter_slice) as c_uchar
}
}
extern "C" fn name<T: FilterPolicy>(state: *mut c_void) -> *const c_char {
unsafe {
let policy = &*(state as *const T);
let name_str = policy.name();
let cstring = CString::new(name_str).unwrap();
cstring.into_raw()
}
}
let ptr = unsafe {
leveldb_filterpolicy_create(
state,
destructor::<T>,
create_filter::<T>,
key_may_match::<T>,
name::<T>,
)
};
let policy = unsafe { *Box::from_raw(state as *mut T) };
CustomFilterPolicy { ptr, policy }
}
pub fn policy(&self) -> &T {
&self.policy
}
}
impl<T: FilterPolicy> LevelDBFilterPolicy for CustomFilterPolicy<T> {
fn raw_ptr(&self) -> *mut leveldb_filterpolicy_t {
self.ptr
}
}
impl<T: FilterPolicy> Drop for CustomFilterPolicy<T> {
fn drop(&mut self) {
unsafe {
leveldb_filterpolicy_destroy(self.ptr);
}
}
}