prefs 0.1.2

Type-safe macOS preferences library
use std::ffi::{CStr, c_char};

#[repr(C)]
pub(crate) struct RawStringArray {
    pub found: bool,
    pub values: *mut *mut c_char,
    pub len: usize,
}

#[repr(C)]
pub(crate) struct BoolResult {
    pub found: bool,
    pub value: bool,
}

#[repr(C)]
pub(crate) struct I64Result {
    pub found: bool,
    pub value: i64,
}

#[repr(C)]
pub(crate) struct F64Result {
    pub found: bool,
    pub value: f64,
}

#[link(name = "prefs_shim", kind = "static")]
unsafe extern "C" {
    fn prefs_get_bool_optional(domain: *const c_char, key: *const c_char) -> BoolResult;
    fn prefs_get_i64_optional(domain: *const c_char, key: *const c_char) -> I64Result;
    fn prefs_get_f64_optional(domain: *const c_char, key: *const c_char) -> F64Result;
    fn prefs_copy_string(domain: *const c_char, key: *const c_char) -> *mut c_char;
    fn prefs_copy_string_array(domain: *const c_char, key: *const c_char) -> RawStringArray;

    fn prefs_set_bool(domain: *const c_char, key: *const c_char, value: bool) -> bool;
    fn prefs_set_i64(domain: *const c_char, key: *const c_char, value: i64) -> bool;
    fn prefs_set_f64(domain: *const c_char, key: *const c_char, value: f64) -> bool;
    fn prefs_set_string(domain: *const c_char, key: *const c_char, value: *const c_char) -> bool;
    fn prefs_set_string_array(
        domain: *const c_char,
        key: *const c_char,
        values: *const *const c_char,
        len: usize,
    ) -> bool;

    fn prefs_remove(domain: *const c_char, key: *const c_char) -> bool;
    fn prefs_contains(domain: *const c_char, key: *const c_char) -> bool;

    fn prefs_free_string(value: *mut c_char);
    fn prefs_free_string_array(array: *mut RawStringArray);
}

pub(crate) fn get_bool_optional(domain: &CStr, key: &CStr) -> BoolResult {
    unsafe { prefs_get_bool_optional(domain.as_ptr(), key.as_ptr()) }
}

pub(crate) fn get_i64_optional(domain: &CStr, key: &CStr) -> I64Result {
    unsafe { prefs_get_i64_optional(domain.as_ptr(), key.as_ptr()) }
}

pub(crate) fn get_f64_optional(domain: &CStr, key: &CStr) -> F64Result {
    unsafe { prefs_get_f64_optional(domain.as_ptr(), key.as_ptr()) }
}

pub(crate) fn copy_string(domain: &CStr, key: &CStr) -> *mut c_char {
    unsafe { prefs_copy_string(domain.as_ptr(), key.as_ptr()) }
}

pub(crate) fn copy_string_array(domain: &CStr, key: &CStr) -> RawStringArray {
    unsafe { prefs_copy_string_array(domain.as_ptr(), key.as_ptr()) }
}

pub(crate) fn set_bool(domain: &CStr, key: &CStr, value: bool) -> bool {
    unsafe { prefs_set_bool(domain.as_ptr(), key.as_ptr(), value) }
}

pub(crate) fn set_i64(domain: &CStr, key: &CStr, value: i64) -> bool {
    unsafe { prefs_set_i64(domain.as_ptr(), key.as_ptr(), value) }
}

pub(crate) fn set_f64(domain: &CStr, key: &CStr, value: f64) -> bool {
    unsafe { prefs_set_f64(domain.as_ptr(), key.as_ptr(), value) }
}

pub(crate) fn set_string(domain: &CStr, key: &CStr, value: &CStr) -> bool {
    unsafe { prefs_set_string(domain.as_ptr(), key.as_ptr(), value.as_ptr()) }
}

pub(crate) fn set_string_array(domain: &CStr, key: &CStr, values: &[&CStr]) -> bool {
    let ptrs: Vec<*const c_char> = values.iter().map(|v| v.as_ptr()).collect();
    unsafe { prefs_set_string_array(domain.as_ptr(), key.as_ptr(), ptrs.as_ptr(), values.len()) }
}

pub(crate) fn remove(domain: &CStr, key: &CStr) -> bool {
    unsafe { prefs_remove(domain.as_ptr(), key.as_ptr()) }
}

pub(crate) fn contains(domain: &CStr, key: &CStr) -> bool {
    unsafe { prefs_contains(domain.as_ptr(), key.as_ptr()) }
}

pub(crate) fn free_string(value: *mut c_char) {
    unsafe { prefs_free_string(value) }
}

pub(crate) fn free_string_array(array: *mut RawStringArray) {
    unsafe { prefs_free_string_array(array) }
}