pmemkv 0.1.3-alpha.0

Rust high-level binding to pmemkv
Documentation
use crate::errors::*;
use pmemkv_sys::KVEngine as KVEngineSys;
use pmemkv_sys::*;
use std::ffi::{CStr, CString};
use std::os::raw::{c_char, c_int, c_void};
use std::slice;

#[derive(Debug, Clone)]
pub struct KVEngine(*mut KVEngineSys);

impl Drop for KVEngine {
    fn drop(&mut self) {
        unsafe {
            kvengine_stop(self.0);
        }
    }
}

type EachFn = Fn(&[c_char], &[c_char]);
type StartFn = Fn(*const c_char, *const c_char, *const c_char);
type StartStringFn = Fn(&str, &str, &str);

extern "C" fn cb_wrapper<F>(closure: *mut c_void, bytes: c_int, v: *const c_char)
where
    F: Fn(&[c_char]),
{
    let opt_closure: &&Fn(&[c_char]) =
        unsafe { &*(closure as *const &dyn std::ops::Fn(&[c_char])) };
    let slice = unsafe { slice::from_raw_parts(v, bytes as usize) };
    opt_closure(slice);
}

extern "C" fn cb_string_wrapper<F>(closure: *mut c_void, _b: c_int, v: *const c_char)
where
    F: Fn(&str),
{
    let opt_closure: &&Fn(&str) = unsafe { &*(closure as *const &dyn std::ops::Fn(&str)) };
    let s = unsafe { CStr::from_ptr(v).to_str().unwrap_or_default() };
    opt_closure(s)
}

extern "C" fn cb_start_wrapper<F>(
    closure: *mut c_void,
    engine: *const c_char,
    config: *const c_char,
    msg: *const c_char,
) where
    F: Fn(*const c_char, *const c_char, *const c_char),
{
    let opt_closure: &&StartFn =
        unsafe { &*(closure as *const &(dyn std::ops::Fn(*const i8, *const i8, *const i8))) };
    opt_closure(engine, config, msg);
}

extern "C" fn cb_start_string_wrapper<F>(
    closure: *mut c_void,
    engine: *const c_char,
    config: *const c_char,
    msg: *const c_char,
) where
    F: Fn(&str, &str, &str),
{
    let opt_closure: &&StartStringFn =
        unsafe { &*(closure as *const &(dyn std::ops::Fn(&str, &str, &str) + 'static)) };
    let (engine_str, config_str, msg_str) = unsafe {
        (
            CStr::from_ptr(engine).to_str().unwrap_or_default(),
            CStr::from_ptr(config).to_str().unwrap_or_default(),
            CStr::from_ptr(msg).to_str().unwrap_or_default(),
        )
    };
    opt_closure(engine_str, config_str, msg_str);
}

extern "C" fn cb_each_wrapper<F>(
    closure: *mut c_void,
    kb: c_int,
    k: *const c_char,
    vb: c_int,
    v: *const c_char,
) where
    F: Fn(&[c_char], &[c_char]),
{
    let opt_closure: &&EachFn =
        unsafe { &*(closure as *const &(dyn std::ops::Fn(&[c_char], &[c_char]))) };
    let (ks, vs) = unsafe {
        (
            slice::from_raw_parts(k, kb as usize),
            slice::from_raw_parts(v, vb as usize),
        )
    };
    opt_closure(ks, vs);
}

extern "C" fn cb_each_string_wrapper<F>(
    closure: *mut c_void,
    _kb: c_int,
    k: *const c_char,
    _vb: c_int,
    v: *const c_char,
) where
    F: Fn(&str, &str),
{
    let opt_closure: &&Fn(&str, &str) =
        unsafe { &*(closure as *const &(dyn std::ops::Fn(&str, &str))) };
    let (k_s, v_s) = unsafe {
        (
            CStr::from_ptr(k).to_str().unwrap_or_default(),
            CStr::from_ptr(v).to_str().unwrap_or_default(),
        )
    };
    opt_closure(k_s, v_s)
}

impl KVEngine {
    pub fn start<F>(engine: &str, config: &str, callback: Option<F>) -> Result<KVEngine>
    where
        F: Fn(*const c_char, *const c_char, *const c_char),
        F: 'static,
    {
        let engine_str = CString::new(engine)?;
        let config_str = CString::new(config)?;
        let kvengine = match callback {
            Some(f) => unsafe {
                let mut cb: &StartFn = &f;
                let cb = &mut cb;
                kvengine_start(
                    cb as *mut _ as *mut c_void,
                    engine_str.as_ptr(),
                    config_str.as_ptr(),
                    Some(cb_start_wrapper::<F>),
                )
            },
            None => unsafe {
                kvengine_start(
                    ::std::ptr::null_mut(),
                    engine_str.as_ptr(),
                    config_str.as_ptr(),
                    None,
                )
            },
        };
        if kvengine.is_null() {
            Err(ErrorKind::Fail.into())
        } else {
            Ok(KVEngine(kvengine))
        }
    }

    pub fn start_string<F>(engine: &str, config: &str, callback: Option<F>) -> Result<KVEngine>
    where
        F: Fn(&str, &str, &str),
        F: 'static,
    {
        let engine_str = CString::new(engine)?;
        let config_str = CString::new(config)?;
        let kvengine = match callback {
            Some(f) => unsafe {
                let mut cb: &StartStringFn = &f;
                let cb = &mut cb;
                kvengine_start(
                    cb as *mut _ as *mut c_void,
                    engine_str.as_ptr(),
                    config_str.as_ptr(),
                    Some(cb_start_string_wrapper::<F>),
                )
            },
            None => unsafe {
                kvengine_start(
                    ::std::ptr::null_mut(),
                    engine_str.as_ptr(),
                    config_str.as_ptr(),
                    None,
                )
            },
        };
        if kvengine.is_null() {
            Err(ErrorKind::Fail.into())
        } else {
            Ok(KVEngine(kvengine))
        }
    }

    pub fn put(&mut self, key: &str, value: &str) -> Result<()> {
        let key_str = CString::new(key)?;
        let val_str = CString::new(value)?;
        let res = unsafe {
            kvengine_put(
                self.0,
                key_str.to_bytes().len() as i32,
                key_str.as_ptr(),
                val_str.to_bytes().len() as i32,
                val_str.as_ptr(),
            )
        };
        if res == 1 {
            Ok(())
        } else if res == -1 {
            Err(ErrorKind::Fail.into())
        } else {
            Err(ErrorKind::NotFound(key.to_string()).into())
        }
    }

    pub fn remove(&mut self, key: &str) -> Result<()> {
        let key_str = CString::new(key)?;
        let res =
            unsafe { kvengine_remove(self.0, key_str.to_bytes().len() as i32, key_str.as_ptr()) };
        if res == 1 {
            Ok(())
        } else if res == -1 {
            Err(ErrorKind::Fail.into())
        } else {
            Err(ErrorKind::NotFound(key.to_string()).into())
        }
    }

    pub fn get<F>(&self, key: &str, callback: Option<F>) -> Result<()>
    where
        F: Fn(&[c_char]),
    {
        let key_str = CString::new(key)?;
        match callback {
            Some(f) => unsafe {
                let mut cb: &Fn(&[c_char]) = &f;
                let cb = &mut cb;
                kvengine_get(
                    self.0,
                    cb as *mut _ as *mut c_void,
                    key_str.to_bytes().len() as i32,
                    key_str.as_ptr(),
                    Some(cb_wrapper::<F>),
                )
            },
            None => unsafe {
                kvengine_get(
                    self.0,
                    ::std::ptr::null_mut(),
                    key_str.to_bytes().len() as i32,
                    key_str.as_ptr(),
                    None,
                )
            },
        }
        Ok(())
    }

    pub fn get_string<F>(&self, key: &str, callback: Option<F>) -> Result<()>
    where
        F: Fn(&str),
    {
        let key_str = CString::new(key)?;
        match callback {
            Some(f) => unsafe {
                let mut cb: &Fn(&str) = &f;
                let cb = &mut cb;
                kvengine_get(
                    self.0,
                    cb as *mut _ as *mut c_void,
                    key_str.to_bytes().len() as i32,
                    key_str.as_ptr(),
                    Some(cb_string_wrapper::<F>),
                )
            },
            None => unsafe {
                kvengine_get(
                    self.0,
                    ::std::ptr::null_mut(),
                    key_str.to_bytes().len() as i32,
                    key_str.as_ptr(),
                    None,
                )
            },
        }
        Ok(())
    }

    pub fn get_copy(&self, key: &str, max_value_bytes: i32) -> Result<String> {
        let key_str = CString::new(key)?;
        let val_vec = Vec::with_capacity(max_value_bytes as usize);
        let res = unsafe {
            kvengine_get_copy(
                self.0,
                key_str.to_bytes().len() as i32,
                key_str.as_ptr(),
                max_value_bytes,
                val_vec.as_ptr() as *mut _,
            )
        };
        if res == 1 {
            Ok(unsafe {
                CStr::from_ptr(val_vec.as_ptr())
                    .to_string_lossy()
                    .into_owned()
            })
        } else if res == -1 {
            Err(ErrorKind::Fail.into())
        } else {
            Err(ErrorKind::NotFound(key.to_string()).into())
        }
    }

    pub fn exists(&self, key: &str) -> Result<()> {
        let key_str = CString::new(key)?;
        let res =
            unsafe { kvengine_exists(self.0, key_str.to_bytes().len() as i32, key_str.as_ptr()) };
        if res == 1 {
            Ok(())
        } else if res == -1 {
            Err(ErrorKind::Fail.into())
        } else {
            Err(ErrorKind::NotFound(key.to_string()).into())
        }
    }

    pub fn each<F>(&self, callback: Option<F>)
    where
        F: Fn(&[c_char], &[c_char]),
        F: 'static,
    {
        match callback {
            Some(f) => unsafe {
                let mut cb: &EachFn = &f;
                let cb = &mut cb;
                kvengine_each(
                    self.0,
                    cb as *mut _ as *mut c_void,
                    Some(cb_each_wrapper::<F>),
                )
            },
            None => unsafe { kvengine_each(self.0, ::std::ptr::null_mut(), None) },
        }
    }

    pub fn each_string<F>(&self, callback: Option<F>)
    where
        F: Fn(&str, &str),
    {
        match callback {
            Some(f) => unsafe {
                let mut cb: &Fn(&str, &str) = &f;
                let cb = &mut cb;
                kvengine_each(
                    self.0,
                    cb as *mut _ as *mut c_void,
                    Some(cb_each_string_wrapper::<F>),
                )
            },
            None => unsafe { kvengine_each(self.0, ::std::ptr::null_mut(), None) },
        }
    }

    pub fn each_above<F>(&self, key: &str, callback: Option<F>) -> Result<()>
    where
        F: Fn(&[c_char], &[c_char]),
        F: 'static,
    {
        let key_str = CString::new(key)?;
        match callback {
            Some(f) => unsafe {
                let mut cb: &EachFn = &f;
                let cb = &mut cb;
                kvengine_each_above(
                    self.0,
                    cb as *mut _ as *mut c_void,
                    key_str.to_bytes().len() as i32,
                    key_str.as_ptr(),
                    Some(cb_each_wrapper::<F>),
                )
            },
            None => unsafe {
                kvengine_each_above(
                    self.0,
                    ::std::ptr::null_mut(),
                    key_str.to_bytes().len() as i32,
                    key_str.as_ptr(),
                    None,
                )
            },
        }
        Ok(())
    }

    pub fn each_above_string<F>(&self, key: &str, callback: Option<F>) -> Result<()>
    where
        F: Fn(&str, &str),
    {
        let key_str = CString::new(key)?;
        match callback {
            Some(f) => unsafe {
                let mut cb: &Fn(&str, &str) = &f;
                let cb = &mut cb;
                kvengine_each_above(
                    self.0,
                    cb as *mut _ as *mut c_void,
                    key_str.to_bytes().len() as i32,
                    key_str.as_ptr(),
                    Some(cb_each_string_wrapper::<F>),
                )
            },
            None => unsafe {
                kvengine_each_above(
                    self.0,
                    ::std::ptr::null_mut(),
                    key_str.to_bytes().len() as i32,
                    key_str.as_ptr(),
                    None,
                )
            },
        }
        Ok(())
    }

    pub fn each_below<F>(&self, key: &str, callback: Option<F>) -> Result<()>
    where
        F: Fn(&[c_char], &[c_char]),
        F: 'static,
    {
        let key_str = CString::new(key)?;
        match callback {
            Some(f) => unsafe {
                let mut cb: &EachFn = &f;
                let cb = &mut cb;
                kvengine_each_below(
                    self.0,
                    cb as *mut _ as *mut c_void,
                    key_str.to_bytes().len() as i32,
                    key_str.as_ptr(),
                    Some(cb_each_wrapper::<F>),
                )
            },
            None => unsafe {
                kvengine_each_below(
                    self.0,
                    ::std::ptr::null_mut(),
                    key_str.to_bytes().len() as i32,
                    key_str.as_ptr(),
                    None,
                )
            },
        }
        Ok(())
    }

    pub fn each_below_string<F>(&self, key: &str, callback: Option<F>) -> Result<()>
    where
        F: Fn(&str, &str),
    {
        let key_str = CString::new(key)?;
        match callback {
            Some(f) => unsafe {
                let mut cb: &Fn(&str, &str) = &f;
                let cb = &mut cb;
                kvengine_each_below(
                    self.0,
                    cb as *mut _ as *mut c_void,
                    key_str.to_bytes().len() as i32,
                    key_str.as_ptr(),
                    Some(cb_each_string_wrapper::<F>),
                )
            },
            None => unsafe {
                kvengine_each_below(
                    self.0,
                    ::std::ptr::null_mut(),
                    key_str.to_bytes().len() as i32,
                    key_str.as_ptr(),
                    None,
                )
            },
        }
        Ok(())
    }

    pub fn each_between<F>(&self, key1: &str, key2: &str, callback: Option<F>) -> Result<()>
    where
        F: Fn(&[c_char], &[c_char]),
        F: 'static,
    {
        let key1_str = CString::new(key1)?;
        let key2_str = CString::new(key2)?;
        match callback {
            Some(f) => unsafe {
                let mut cb: &EachFn = &f;
                let cb = &mut cb;
                kvengine_each_between(
                    self.0,
                    cb as *mut _ as *mut c_void,
                    key1_str.to_bytes().len() as i32,
                    key1_str.as_ptr(),
                    key2_str.to_bytes().len() as i32,
                    key2_str.as_ptr(),
                    Some(cb_each_wrapper::<F>),
                )
            },
            None => unsafe {
                kvengine_each_between(
                    self.0,
                    ::std::ptr::null_mut(),
                    key1_str.to_bytes().len() as i32,
                    key1_str.as_ptr(),
                    key2_str.to_bytes().len() as i32,
                    key2_str.as_ptr(),
                    None,
                )
            },
        }
        Ok(())
    }

    pub fn each_between_string<F>(&self, key1: &str, key2: &str, callback: Option<F>) -> Result<()>
    where
        F: Fn(&str, &str),
    {
        let key1_str = CString::new(key1)?;
        let key2_str = CString::new(key2)?;
        match callback {
            Some(f) => unsafe {
                let mut cb: &Fn(&str, &str) = &f;
                let cb = &mut cb;
                kvengine_each_between(
                    self.0,
                    cb as *mut _ as *mut c_void,
                    key1_str.to_bytes().len() as i32,
                    key1_str.as_ptr(),
                    key2_str.to_bytes().len() as i32,
                    key2_str.as_ptr(),
                    Some(cb_each_string_wrapper::<F>),
                )
            },
            None => unsafe {
                kvengine_each_between(
                    self.0,
                    ::std::ptr::null_mut(),
                    key1_str.to_bytes().len() as i32,
                    key1_str.as_ptr(),
                    key2_str.to_bytes().len() as i32,
                    key2_str.as_ptr(),
                    None,
                )
            },
        }
        Ok(())
    }

    pub fn count(&self) -> i64 {
        unsafe { kvengine_count(self.0) }
    }

    pub fn count_above(&self, key: &str) -> Result<i64> {
        let key_str = CString::new(key)?;
        Ok(unsafe {
            kvengine_count_above(self.0, key_str.to_bytes().len() as i32, key_str.as_ptr())
        })
    }

    pub fn count_below(&self, key: &str) -> Result<i64> {
        let key_str = CString::new(key)?;
        Ok(unsafe {
            kvengine_count_below(self.0, key_str.to_bytes().len() as i32, key_str.as_ptr())
        })
    }

    pub fn count_between(&self, key1: &str, key2: &str) -> Result<i64> {
        let key1_str = CString::new(key1)?;
        let key2_str = CString::new(key2)?;
        Ok(unsafe {
            kvengine_count_between(
                self.0,
                key1_str.to_bytes().len() as i32,
                key1_str.as_ptr(),
                key2_str.to_bytes().len() as i32,
                key2_str.as_ptr(),
            )
        })
    }

    pub fn all<F>(&mut self, callback: Option<F>)
    where
        F: Fn(&[c_char]),
    {
        match callback {
            Some(f) => unsafe {
                let mut cb: &F = &f;
                let cb = &mut cb;
                kvengine_all(self.0, cb as *mut _ as *mut c_void, Some(cb_wrapper::<F>))
            },
            None => unsafe { kvengine_all(self.0, ::std::ptr::null_mut(), None) },
        }
    }

    pub fn all_string<F>(&mut self, callback: Option<F>)
    where
        F: Fn(&str),
    {
        match callback {
            Some(f) => unsafe {
                let mut cb: &Fn(&str) = &f;
                let cb = &mut cb;
                kvengine_all(
                    self.0,
                    cb as *mut _ as *mut c_void,
                    Some(cb_string_wrapper::<F>),
                )
            },
            None => unsafe { kvengine_all(self.0, ::std::ptr::null_mut(), None) },
        }
    }

    pub fn all_above<F>(&mut self, key: &str, callback: Option<F>) -> Result<()>
    where
        F: Fn(&[c_char]),
    {
        let key_str = CString::new(key)?;
        match callback {
            Some(f) => {
                unsafe {
                    let mut cb: &Fn(&[c_char]) = &f;
                    let cb = &mut cb;
                    kvengine_all_above(
                        self.0,
                        cb as *mut _ as *mut c_void,
                        key_str.to_bytes().len() as i32,
                        key_str.as_ptr(),
                        Some(cb_wrapper::<F>),
                    )
                }
                Ok(())
            }
            None => {
                unsafe {
                    kvengine_all_above(
                        self.0,
                        ::std::ptr::null_mut(),
                        key_str.to_bytes().len() as i32,
                        key_str.as_ptr(),
                        None,
                    )
                }
                Ok(())
            }
        }
    }

    pub fn all_above_string<F>(&mut self, key: &str, callback: Option<F>) -> Result<()>
    where
        F: Fn(&str),
    {
        let key_str = CString::new(key)?;
        match callback {
            Some(f) => {
                unsafe {
                    let mut cb: &Fn(&str) = &f;
                    let cb = &mut cb;
                    kvengine_all_above(
                        self.0,
                        cb as *mut _ as *mut c_void,
                        key_str.to_bytes().len() as i32,
                        key_str.as_ptr(),
                        Some(cb_string_wrapper::<F>),
                    )
                }
                Ok(())
            }
            None => {
                unsafe {
                    kvengine_all_above(
                        self.0,
                        ::std::ptr::null_mut(),
                        key_str.to_bytes().len() as i32,
                        key_str.as_ptr(),
                        None,
                    )
                }
                Ok(())
            }
        }
    }

    pub fn all_below<F>(&mut self, key: &str, callback: Option<F>) -> Result<()>
    where
        F: Fn(&[c_char]),
    {
        let key_str = CString::new(key)?;
        match callback {
            Some(f) => {
                unsafe {
                    let mut cb: &Fn(&[c_char]) = &f;
                    let cb = &mut cb;
                    kvengine_all_below(
                        self.0,
                        cb as *mut _ as *mut c_void,
                        key_str.to_bytes().len() as i32,
                        key_str.as_ptr(),
                        Some(cb_wrapper::<F>),
                    )
                }
                Ok(())
            }
            None => {
                unsafe {
                    kvengine_all_below(
                        self.0,
                        ::std::ptr::null_mut(),
                        key_str.to_bytes().len() as i32,
                        key_str.as_ptr(),
                        None,
                    )
                }
                Ok(())
            }
        }
    }

    pub fn all_below_string<F>(&mut self, key: &str, callback: Option<F>) -> Result<()>
    where
        F: Fn(&str),
    {
        let key_str = CString::new(key)?;
        match callback {
            Some(f) => {
                unsafe {
                    let mut cb: &Fn(&str) = &f;
                    let cb = &mut cb;
                    kvengine_all_below(
                        self.0,
                        cb as *mut _ as *mut c_void,
                        key_str.to_bytes().len() as i32,
                        key_str.as_ptr(),
                        Some(cb_string_wrapper::<F>),
                    )
                }
                Ok(())
            }
            None => {
                unsafe {
                    kvengine_all_below(
                        self.0,
                        ::std::ptr::null_mut(),
                        key_str.to_bytes().len() as i32,
                        key_str.as_ptr(),
                        None,
                    )
                }
                Ok(())
            }
        }
    }

    pub fn all_between<F>(&mut self, key1: &str, key2: &str, callback: Option<F>) -> Result<()>
    where
        F: Fn(&[c_char]),
    {
        let key1_str = CString::new(key1)?;
        let key2_str = CString::new(key2)?;
        match callback {
            Some(f) => {
                unsafe {
                    let mut cb: &Fn(&[c_char]) = &f;
                    let cb = &mut cb;
                    kvengine_all_between(
                        self.0,
                        cb as *mut _ as *mut c_void,
                        key1_str.to_bytes().len() as i32,
                        key1_str.as_ptr(),
                        key2_str.to_bytes().len() as i32,
                        key2_str.as_ptr(),
                        Some(cb_wrapper::<F>),
                    )
                }
                Ok(())
            }
            None => {
                unsafe {
                    kvengine_all_between(
                        self.0,
                        ::std::ptr::null_mut(),
                        key1_str.to_bytes().len() as i32,
                        key1_str.as_ptr(),
                        key2_str.to_bytes().len() as i32,
                        key2_str.as_ptr(),
                        None,
                    )
                }
                Ok(())
            }
        }
    }

    pub fn all_between_string<F>(
        &mut self,
        key1: &str,
        key2: &str,
        callback: Option<F>,
    ) -> Result<()>
    where
        F: Fn(&str),
    {
        let key1_str = CString::new(key1)?;
        let key2_str = CString::new(key2)?;
        match callback {
            Some(f) => {
                unsafe {
                    let mut cb: &Fn(&str) = &f;
                    let cb = &mut cb;
                    kvengine_all_between(
                        self.0,
                        cb as *mut _ as *mut c_void,
                        key1_str.to_bytes().len() as i32,
                        key1_str.as_ptr(),
                        key2_str.to_bytes().len() as i32,
                        key2_str.as_ptr(),
                        Some(cb_string_wrapper::<F>),
                    )
                }
                Ok(())
            }
            None => {
                unsafe {
                    kvengine_all_between(
                        self.0,
                        ::std::ptr::null_mut(),
                        key1_str.to_bytes().len() as i32,
                        key1_str.as_ptr(),
                        key2_str.to_bytes().len() as i32,
                        key2_str.as_ptr(),
                        None,
                    )
                }
                Ok(())
            }
        }
    }
}