use crate::embedded::c_api::error::linkrs_error_code_t;
use crate::embedded::c_api::types::linkrs_config_t;
use crate::embedded::{DatabaseConfig, SyncMode};
use std::ffi::{c_char, c_int, CStr};
use std::time::Duration;
pub struct LinkrsConfigHandle {
pub(crate) inner: DatabaseConfig,
}
impl LinkrsConfigHandle {
pub fn new(inner: DatabaseConfig) -> Self {
Self { inner }
}
}
#[no_mangle]
pub unsafe extern "C" fn linkrs_config_new() -> *mut linkrs_config_t {
let config = DatabaseConfig::memory();
let handle = Box::new(LinkrsConfigHandle::new(config));
Box::into_raw(handle) as *mut linkrs_config_t
}
#[no_mangle]
pub unsafe extern "C" fn linkrs_config_file(path: *const c_char) -> *mut linkrs_config_t {
if path.is_null() {
return std::ptr::null_mut();
}
let path_str = match CStr::from_ptr(path).to_str() {
Ok(s) => s,
Err(_) => return std::ptr::null_mut(),
};
let config = DatabaseConfig::file(path_str);
let handle = Box::new(LinkrsConfigHandle::new(config));
Box::into_raw(handle) as *mut linkrs_config_t
}
#[no_mangle]
pub unsafe extern "C" fn linkrs_config_memory() -> *mut linkrs_config_t {
let config = DatabaseConfig::memory();
let handle = Box::new(LinkrsConfigHandle::new(config));
Box::into_raw(handle) as *mut linkrs_config_t
}
#[no_mangle]
pub unsafe extern "C" fn linkrs_config_free(config: *mut linkrs_config_t) -> c_int {
if config.is_null() {
return linkrs_error_code_t::LINKRS_MISUSE as c_int;
}
let _ = Box::from_raw(config as *mut LinkrsConfigHandle);
linkrs_error_code_t::LINKRS_OK as c_int
}
#[no_mangle]
pub unsafe extern "C" fn linkrs_config_set_cache_size(
config: *mut linkrs_config_t,
size_mb: c_int,
) -> c_int {
if config.is_null() || size_mb <= 0 {
return linkrs_error_code_t::LINKRS_MISUSE as c_int;
}
let handle = &mut *(config as *mut LinkrsConfigHandle);
handle.inner = handle.inner.clone().with_cache_size(size_mb as usize);
linkrs_error_code_t::LINKRS_OK as c_int
}
#[no_mangle]
pub unsafe extern "C" fn linkrs_config_set_timeout(
config: *mut linkrs_config_t,
timeout_ms: c_int,
) -> c_int {
if config.is_null() || timeout_ms < 0 {
return linkrs_error_code_t::LINKRS_MISUSE as c_int;
}
let handle = &mut *(config as *mut LinkrsConfigHandle);
handle.inner = handle
.inner
.clone()
.with_timeout(Duration::from_millis(timeout_ms as u64));
linkrs_error_code_t::LINKRS_OK as c_int
}
#[no_mangle]
pub unsafe extern "C" fn linkrs_config_set_read_only(
config: *mut linkrs_config_t,
read_only: c_int,
) -> c_int {
if config.is_null() {
return linkrs_error_code_t::LINKRS_MISUSE as c_int;
}
let handle = &mut *(config as *mut LinkrsConfigHandle);
handle.inner = handle.inner.clone().with_read_only(read_only != 0);
linkrs_error_code_t::LINKRS_OK as c_int
}
#[no_mangle]
pub unsafe extern "C" fn linkrs_config_set_create_if_missing(
config: *mut linkrs_config_t,
create: c_int,
) -> c_int {
if config.is_null() {
return linkrs_error_code_t::LINKRS_MISUSE as c_int;
}
let handle = &mut *(config as *mut LinkrsConfigHandle);
handle.inner = handle.inner.clone().with_create_if_missing(create != 0);
linkrs_error_code_t::LINKRS_OK as c_int
}
#[no_mangle]
pub unsafe extern "C" fn linkrs_config_set_enable_wal(
config: *mut linkrs_config_t,
enable: c_int,
) -> c_int {
if config.is_null() {
return linkrs_error_code_t::LINKRS_MISUSE as c_int;
}
let handle = &mut *(config as *mut LinkrsConfigHandle);
handle.inner = handle.inner.clone().with_wal(enable != 0);
linkrs_error_code_t::LINKRS_OK as c_int
}
#[no_mangle]
pub unsafe extern "C" fn linkrs_config_set_sync_mode(
config: *mut linkrs_config_t,
mode: c_int,
) -> c_int {
if config.is_null() {
return linkrs_error_code_t::LINKRS_MISUSE as c_int;
}
let sync_mode = match mode {
0 => SyncMode::Full,
1 => SyncMode::Normal,
2 => SyncMode::Off,
_ => return linkrs_error_code_t::LINKRS_MISUSE as c_int,
};
let handle = &mut *(config as *mut LinkrsConfigHandle);
handle.inner = handle.inner.clone().with_sync_mode(sync_mode);
linkrs_error_code_t::LINKRS_OK as c_int
}
#[cfg(test)]
mod tests {
use super::*;
use std::ffi::CString;
#[test]
fn test_config_new() {
unsafe {
let config = linkrs_config_new();
assert!(!config.is_null());
assert_eq!(linkrs_config_free(config), 0);
}
}
#[test]
fn test_config_file() {
unsafe {
let path = CString::new("test.db").unwrap();
let config = linkrs_config_file(path.as_ptr());
assert!(!config.is_null());
assert_eq!(linkrs_config_free(config), 0);
}
}
#[test]
fn test_config_memory() {
unsafe {
let config = linkrs_config_memory();
assert!(!config.is_null());
assert_eq!(linkrs_config_free(config), 0);
}
}
#[test]
fn test_config_set_cache_size() {
unsafe {
let config = linkrs_config_memory();
assert_eq!(linkrs_config_set_cache_size(config, 128), 0);
assert_eq!(linkrs_config_free(config), 0);
}
}
#[test]
fn test_config_set_timeout() {
unsafe {
let config = linkrs_config_memory();
assert_eq!(linkrs_config_set_timeout(config, 5000), 0);
assert_eq!(linkrs_config_free(config), 0);
}
}
#[test]
fn test_config_sync_mode_values() {
unsafe {
let config = linkrs_config_memory();
assert_eq!(linkrs_config_set_sync_mode(config, 0), 0);
assert_eq!(linkrs_config_set_sync_mode(config, 1), 0);
assert_eq!(linkrs_config_set_sync_mode(config, 2), 0);
assert_eq!(
linkrs_config_set_sync_mode(config, 7),
linkrs_error_code_t::LINKRS_MISUSE as c_int
);
assert_eq!(
linkrs_config_set_sync_mode(std::ptr::null_mut(), 1),
linkrs_error_code_t::LINKRS_MISUSE as c_int
);
assert_eq!(linkrs_config_free(config), 0);
}
}
#[test]
fn test_open_with_config_memory() {
use crate::embedded::c_api::database::{linkrs_close, linkrs_open_with_config};
use crate::embedded::c_api::types::linkrs_t;
unsafe {
let config = linkrs_config_memory();
assert!(!config.is_null());
let mut db: *mut linkrs_t = std::ptr::null_mut();
assert_eq!(linkrs_open_with_config(config, &mut db), 0);
assert!(!db.is_null());
assert_eq!(linkrs_close(db), 0);
assert_eq!(linkrs_config_free(config), 0);
let mut db: *mut linkrs_t = std::ptr::null_mut();
assert_eq!(
linkrs_open_with_config(std::ptr::null_mut(), &mut db),
linkrs_error_code_t::LINKRS_MISUSE as c_int
);
}
}
}