collectd_plugin/api/
oconfig.rs

1use crate::bindings::{
2    oconfig_item_t, oconfig_value_s__bindgen_ty_1, oconfig_value_t, OCONFIG_TYPE_BOOLEAN,
3    OCONFIG_TYPE_NUMBER, OCONFIG_TYPE_STRING,
4};
5use crate::errors::ConfigError;
6use std::ffi::CStr;
7use std::slice;
8
9/// A parsed value from the Collectd config
10#[derive(Debug, PartialEq, Clone)]
11pub enum ConfigValue<'a> {
12    /// Numeric value
13    Number(f64),
14
15    /// True / false, on / off
16    Boolean(bool),
17
18    /// Contents enclosed in quote
19    String(&'a str),
20}
21
22/// Parsed key, values, children objects from the Collectd config.
23#[derive(Debug, PartialEq, Clone)]
24pub struct ConfigItem<'a> {
25    /// Key of the field, does not have to be unique
26    pub key: &'a str,
27
28    /// Values on the same line as the key
29    pub values: Vec<ConfigValue<'a>>,
30
31    /// Sub elements
32    pub children: Vec<ConfigItem<'a>>,
33}
34
35impl ConfigValue<'_> {
36    /// # Safety
37    ///
38    /// Assumed that the any pointers are non null
39    pub unsafe fn from(value: &oconfig_value_t) -> Result<ConfigValue<'_>, ConfigError> {
40        match value.value {
41            oconfig_value_s__bindgen_ty_1 { string }
42                if value.type_ == OCONFIG_TYPE_STRING as i32 =>
43            {
44                Ok(ConfigValue::String(
45                    CStr::from_ptr(string)
46                        .to_str()
47                        .map_err(ConfigError::StringDecode)?,
48                ))
49            }
50            oconfig_value_s__bindgen_ty_1 { number }
51                if value.type_ == OCONFIG_TYPE_NUMBER as i32 =>
52            {
53                Ok(ConfigValue::Number(number))
54            }
55            oconfig_value_s__bindgen_ty_1 { boolean }
56                if value.type_ == OCONFIG_TYPE_BOOLEAN as i32 =>
57            {
58                Ok(ConfigValue::Boolean(boolean != 0))
59            }
60            _ => Err(ConfigError::UnknownType(value.type_)),
61        }
62    }
63}
64
65impl ConfigItem<'_> {
66    /// # Safety
67    ///
68    /// Assumed that the pointer is non-null
69    pub unsafe fn from(item: &oconfig_item_t) -> Result<ConfigItem, ConfigError> {
70        let key = CStr::from_ptr(item.key)
71            .to_str()
72            .map_err(ConfigError::StringDecode)?;
73
74        let values = if !item.values.is_null() {
75            slice::from_raw_parts(item.values, item.values_num.max(0) as usize)
76                .iter()
77                .map(|x| ConfigValue::from(x))
78                .collect::<Result<Vec<_>, _>>()?
79        } else {
80            Vec::new()
81        };
82
83        let children = if !item.children.is_null() {
84            slice::from_raw_parts(item.children, item.children_num.max(0) as usize)
85                .iter()
86                .map(|x| ConfigItem::from(x))
87                .collect::<Result<Vec<_>, _>>()?
88        } else {
89            Vec::new()
90        };
91
92        Ok(ConfigItem {
93            key,
94            values,
95            children,
96        })
97    }
98}