use crate::bindings as ffi;
use crate::error::{CpdbError, Result};
use crate::util;
use glib_sys::{GHashTableIter, g_hash_table_iter_init, g_hash_table_iter_next};
use std::mem::MaybeUninit;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OptionInfo {
pub name: String,
pub default_value: String,
pub group: String,
pub supported_values: Vec<String>,
}
#[derive(Debug, Clone, Default)]
pub struct OptionsCollection {
pub options: Vec<OptionInfo>,
}
impl OptionsCollection {
pub unsafe fn from_raw(raw: *mut ffi::cpdb_options_t) -> Result<Self> {
if raw.is_null() {
return Err(CpdbError::NullPointer);
}
let table = unsafe { (*raw).table };
if table.is_null() {
return Ok(Self::default());
}
let mut options: Vec<OptionInfo> = Vec::new();
unsafe {
let mut iter = MaybeUninit::<GHashTableIter>::uninit();
g_hash_table_iter_init(iter.as_mut_ptr(), table as *mut glib_sys::GHashTable);
let mut iter = iter.assume_init();
let mut key: *mut libc::c_void = std::ptr::null_mut();
let mut value: *mut libc::c_void = std::ptr::null_mut();
while g_hash_table_iter_next(&mut iter, &mut key, &mut value) != 0 {
if value.is_null() {
continue;
}
let opt = value as *mut ffi::cpdb_option_t;
let name = util::cstr_to_string((*opt).option_name).unwrap_or_default();
let default_value = util::cstr_to_string((*opt).default_value).unwrap_or_default();
let group = util::cstr_to_string((*opt).group_name).unwrap_or_default();
let mut supported_values: Vec<String> =
Vec::with_capacity((*opt).num_supported as usize);
if !(*opt).supported_values.is_null() && (*opt).num_supported > 0 {
for i in 0..((*opt).num_supported as usize) {
let s_ptr = *(*opt).supported_values.add(i);
if !s_ptr.is_null() {
if let Ok(s) = util::cstr_to_string(s_ptr) {
supported_values.push(s);
}
}
}
}
options.push(OptionInfo {
name,
default_value,
group,
supported_values,
});
}
}
Ok(Self { options })
}
pub fn len(&self) -> usize {
self.options.len()
}
pub fn is_empty(&self) -> bool {
self.options.is_empty()
}
pub fn get(&self, name: &str) -> Option<&OptionInfo> {
self.options.iter().find(|o| o.name == name)
}
pub fn iter(&self) -> impl Iterator<Item = &OptionInfo> {
self.options.iter()
}
}