1use crate::bindings as ffi;
4use crate::error::{CpdbError, Result};
5use crate::util;
6use glib_sys::{GHashTableIter, g_hash_table_iter_init, g_hash_table_iter_next};
7use std::mem::MaybeUninit;
8
9#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct OptionInfo {
12 pub name: String,
14 pub default_value: String,
16 pub group: String,
18 pub supported_values: Vec<String>,
20}
21
22#[derive(Debug, Clone, Default)]
24pub struct OptionsCollection {
25 pub options: Vec<OptionInfo>,
27}
28
29impl OptionsCollection {
30 pub unsafe fn from_raw(raw: *mut ffi::cpdb_options_t) -> Result<Self> {
37 if raw.is_null() {
38 return Err(CpdbError::NullPointer);
39 }
40
41 let table = unsafe { (*raw).table };
42
43 if table.is_null() {
44 return Ok(Self::default());
45 }
46
47 let mut options: Vec<OptionInfo> = Vec::new();
48
49 unsafe {
50 let mut iter = MaybeUninit::<GHashTableIter>::uninit();
51 g_hash_table_iter_init(iter.as_mut_ptr(), table as *mut glib_sys::GHashTable);
52 let mut iter = iter.assume_init();
53
54 let mut key: *mut libc::c_void = std::ptr::null_mut();
55 let mut value: *mut libc::c_void = std::ptr::null_mut();
56
57 while g_hash_table_iter_next(&mut iter, &mut key, &mut value) != 0 {
58 if value.is_null() {
59 continue;
60 }
61 let opt = value as *mut ffi::cpdb_option_t;
62
63 let name = util::cstr_to_string((*opt).option_name).unwrap_or_default();
64 let default_value = util::cstr_to_string((*opt).default_value).unwrap_or_default();
65 let group = util::cstr_to_string((*opt).group_name).unwrap_or_default();
66
67 let mut supported_values: Vec<String> =
68 Vec::with_capacity((*opt).num_supported as usize);
69
70 if !(*opt).supported_values.is_null() && (*opt).num_supported > 0 {
71 for i in 0..((*opt).num_supported as usize) {
72 let s_ptr = *(*opt).supported_values.add(i);
73 if !s_ptr.is_null() {
74 if let Ok(s) = util::cstr_to_string(s_ptr) {
75 supported_values.push(s);
76 }
77 }
78 }
79 }
80
81 options.push(OptionInfo {
82 name,
83 default_value,
84 group,
85 supported_values,
86 });
87 }
88 }
89
90 Ok(Self { options })
91 }
92
93 pub fn len(&self) -> usize {
95 self.options.len()
96 }
97
98 pub fn is_empty(&self) -> bool {
100 self.options.is_empty()
101 }
102
103 pub fn get(&self, name: &str) -> Option<&OptionInfo> {
105 self.options.iter().find(|o| o.name == name)
106 }
107
108 pub fn iter(&self) -> impl Iterator<Item = &OptionInfo> {
110 self.options.iter()
111 }
112}