use crate::error::Wrap;
use crate::ffi::unqlite_config;
use libc::strlen;
use std::ffi::CString;
use std::mem;
use std::os::raw::c_char;
use std::ptr;
use crate::vars::{
UNQLITE_CONFIG_DISABLE_AUTO_COMMIT, UNQLITE_CONFIG_ERR_LOG, UNQLITE_CONFIG_GET_KV_NAME,
UNQLITE_CONFIG_JX9_ERR_LOG, UNQLITE_CONFIG_KV_ENGINE, UNQLITE_CONFIG_MAX_PAGE_CACHE,
};
use crate::UnQLite;
pub trait Config {
fn max_page_cache(self, max: u32) -> Self;
fn disable_auto_commit(self) -> Self;
fn kv_engine<S: Into<Vec<u8>>>(self, name: S) -> Self;
fn err_log(&self) -> Option<String>;
fn jx9_err_log(&self) -> Option<String>;
fn kv_name(&self) -> String;
}
impl Config for UnQLite {
fn max_page_cache(self, max: u32) -> Self {
wrap_raw!(self, config, UNQLITE_CONFIG_MAX_PAGE_CACHE, max)
.expect("set max page cache error");
self
}
fn disable_auto_commit(self) -> Self {
wrap_raw!(self, config, UNQLITE_CONFIG_DISABLE_AUTO_COMMIT).expect("disable auto commit");
self
}
fn kv_engine<S: Into<Vec<u8>>>(self, name: S) -> Self {
let name = CString::new(name).expect("KV engine error").into_raw();
wrap_raw!(self, config, UNQLITE_CONFIG_KV_ENGINE, name).expect("config KV engine");
self
}
fn err_log(&self) -> Option<String> {
let log: *mut c_char = unsafe { mem::MaybeUninit::uninit().assume_init() };
let len: i32 = unsafe { mem::MaybeUninit::uninit().assume_init() };
wrap_raw!(self, config, UNQLITE_CONFIG_ERR_LOG, &log, &len)
.ok()
.and_then(|_| {
if len > 0 {
Some(from_chars_to_string(log))
} else {
None
}
})
}
fn jx9_err_log(&self) -> Option<String> {
let log: *mut c_char = unsafe { mem::MaybeUninit::uninit().assume_init() };
let len: i32 = unsafe { mem::MaybeUninit::uninit().assume_init() };
wrap_raw!(self, config, UNQLITE_CONFIG_JX9_ERR_LOG, &log, &len)
.ok()
.and_then(|_| {
if len > 0 {
Some(from_chars_to_string(log))
} else {
None
}
})
}
fn kv_name(&self) -> String {
let kv_name: *mut c_char = unsafe { mem::MaybeUninit::uninit().assume_init() };
wrap_raw!(self, config, UNQLITE_CONFIG_GET_KV_NAME, &kv_name).unwrap();
from_chars_to_string(kv_name)
}
}
fn from_chars_to_cstring(p: *mut c_char) -> CString {
unsafe {
let len = strlen(p);
let (_, vec) = (0..len).fold((p, Vec::new()), |(p, mut vec), _| {
let u: u8 = ptr::read(p) as u8;
vec.push(u);
let p = p.offset(1);
(p, vec)
});
CString::from_vec_unchecked(vec)
}
}
fn from_chars_to_string(p: *mut c_char) -> String {
from_chars_to_cstring(p).into_string().unwrap()
}
#[cfg(test)]
#[cfg(feature = "enable-threads")]
mod tests {
use super::Config;
use crate::UnQLite;
#[test]
fn max_page_cache() {
let unqlite = UnQLite::create_temp().max_page_cache(512000000);
let kv_name = unqlite.kv_name();
assert_eq!(kv_name, String::from("mem"));
assert_eq!(unqlite.err_log(), None);
}
#[test]
fn disable_auto_commit() {
let _ = UnQLite::create_temp()
.max_page_cache(4096u32)
.disable_auto_commit();
}
#[test]
#[should_panic]
fn kv_engine_panic() {
let _ = UnQLite::create_temp().kv_engine("hash");
}
}