use std::ffi::{CStr, CString, c_char};
use crate::error::{Error, Result};
use crate::raw;
pub trait PreferenceValue: Sized {
fn get(domain: &CStr, key: &CStr) -> Result<Option<Self>>;
fn set(domain: &CStr, key: &CStr, value: &Self) -> Result<()>;
fn remove(domain: &CStr, key: &CStr) -> Result<()>;
fn contains(domain: &CStr, key: &CStr) -> Result<bool>;
}
impl PreferenceValue for bool {
fn get(domain: &CStr, key: &CStr) -> Result<Option<Self>> {
let result = raw::get_bool_optional(domain, key);
if result.found {
Ok(Some(result.value))
} else {
Ok(None)
}
}
fn set(domain: &CStr, key: &CStr, value: &Self) -> Result<()> {
if raw::set_bool(domain, key, *value) {
Ok(())
} else {
Err(Error::WriteFailed)
}
}
fn remove(domain: &CStr, key: &CStr) -> Result<()> {
if raw::remove(domain, key) {
Ok(())
} else {
Err(Error::WriteFailed)
}
}
fn contains(domain: &CStr, key: &CStr) -> Result<bool> {
Ok(raw::contains(domain, key))
}
}
impl PreferenceValue for i64 {
fn get(domain: &CStr, key: &CStr) -> Result<Option<Self>> {
let result = raw::get_i64_optional(domain, key);
if result.found {
Ok(Some(result.value))
} else {
Ok(None)
}
}
fn set(domain: &CStr, key: &CStr, value: &Self) -> Result<()> {
if raw::set_i64(domain, key, *value) {
Ok(())
} else {
Err(Error::WriteFailed)
}
}
fn remove(domain: &CStr, key: &CStr) -> Result<()> {
if raw::remove(domain, key) {
Ok(())
} else {
Err(Error::WriteFailed)
}
}
fn contains(domain: &CStr, key: &CStr) -> Result<bool> {
Ok(raw::contains(domain, key))
}
}
impl PreferenceValue for f64 {
fn get(domain: &CStr, key: &CStr) -> Result<Option<Self>> {
let result = raw::get_f64_optional(domain, key);
if result.found {
Ok(Some(result.value))
} else {
Ok(None)
}
}
fn set(domain: &CStr, key: &CStr, value: &Self) -> Result<()> {
if raw::set_f64(domain, key, *value) {
Ok(())
} else {
Err(Error::WriteFailed)
}
}
fn remove(domain: &CStr, key: &CStr) -> Result<()> {
if raw::remove(domain, key) {
Ok(())
} else {
Err(Error::WriteFailed)
}
}
fn contains(domain: &CStr, key: &CStr) -> Result<bool> {
Ok(raw::contains(domain, key))
}
}
impl PreferenceValue for String {
fn get(domain: &CStr, key: &CStr) -> Result<Option<Self>> {
let ptr = raw::copy_string(domain, key);
if ptr.is_null() {
return Ok(None);
}
let _guard = RawStringGuard(ptr);
Ok(Some(
unsafe { CStr::from_ptr(ptr) }
.to_string_lossy()
.into_owned(),
))
}
fn set(domain: &CStr, key: &CStr, value: &Self) -> Result<()> {
let cstr = CString::new(value.as_str())?;
if raw::set_string(domain, key, &cstr) {
Ok(())
} else {
Err(Error::WriteFailed)
}
}
fn remove(domain: &CStr, key: &CStr) -> Result<()> {
if raw::remove(domain, key) {
Ok(())
} else {
Err(Error::WriteFailed)
}
}
fn contains(domain: &CStr, key: &CStr) -> Result<bool> {
Ok(raw::contains(domain, key))
}
}
impl PreferenceValue for Vec<String> {
fn get(domain: &CStr, key: &CStr) -> Result<Option<Self>> {
let mut raw_array = raw::copy_string_array(domain, key);
let _guard = RawStringArrayGuard(std::ptr::addr_of_mut!(raw_array));
if !raw_array.found {
return Ok(None);
}
let mut values = Vec::with_capacity(raw_array.len);
if raw_array.values.is_null() || raw_array.len == 0 {
return Ok(Some(values));
}
let raw_values = unsafe { std::slice::from_raw_parts(raw_array.values, raw_array.len) };
for value in raw_values {
if value.is_null() {
continue;
}
values.push(
unsafe { CStr::from_ptr(*value) }
.to_string_lossy()
.into_owned(),
);
}
Ok(Some(values))
}
fn set(domain: &CStr, key: &CStr, value: &Self) -> Result<()> {
let cstrings: Vec<CString> = value
.iter()
.map(|s| CString::new(s.as_str()))
.collect::<std::result::Result<Vec<_>, _>>()?;
let refs: Vec<&CStr> = cstrings.iter().map(CString::as_c_str).collect();
if raw::set_string_array(domain, key, &refs) {
Ok(())
} else {
Err(Error::WriteFailed)
}
}
fn remove(domain: &CStr, key: &CStr) -> Result<()> {
if raw::remove(domain, key) {
Ok(())
} else {
Err(Error::WriteFailed)
}
}
fn contains(domain: &CStr, key: &CStr) -> Result<bool> {
Ok(raw::contains(domain, key))
}
}
struct RawStringGuard(*mut c_char);
impl Drop for RawStringGuard {
fn drop(&mut self) {
raw::free_string(self.0);
}
}
struct RawStringArrayGuard(*mut raw::RawStringArray);
impl Drop for RawStringArrayGuard {
fn drop(&mut self) {
raw::free_string_array(self.0);
}
}