use std::{ffi::CStr, marker::PhantomData, ptr::NonNull};
use crate::{cstring, sys};
pub struct XmlConfig {
root: NonNull<sys::switch_xml>,
settings: Option<NonNull<sys::switch_xml>>,
}
impl XmlConfig {
pub fn open(file: impl AsRef<str>) -> Option<Self> {
let file = cstring(file).ok()?;
let mut settings = std::ptr::null_mut();
let root =
unsafe { sys::switch_xml_open_cfg(file.as_ptr(), &mut settings, std::ptr::null_mut()) };
let root = NonNull::new(root)?;
Some(Self {
root,
settings: NonNull::new(settings),
})
}
pub fn settings(&self) -> Option<XmlNode<'_>> {
self.settings.map(XmlNode::new)
}
}
impl Drop for XmlConfig {
fn drop(&mut self) {
unsafe {
sys::switch_xml_free(self.root.as_ptr());
}
}
}
#[derive(Copy, Clone)]
pub struct XmlNode<'a> {
raw: NonNull<sys::switch_xml>,
_owner: PhantomData<&'a XmlConfig>,
}
impl<'a> XmlNode<'a> {
fn new(raw: NonNull<sys::switch_xml>) -> Self {
Self {
raw,
_owner: PhantomData,
}
}
pub fn child(self, name: impl AsRef<str>) -> Option<Self> {
let name = cstring(name).ok()?;
let child = unsafe { sys::switch_xml_child(self.raw.as_ptr(), name.as_ptr()) };
NonNull::new(child).map(Self::new)
}
pub fn next(self) -> Option<Self> {
NonNull::new(unsafe { (*self.raw.as_ptr()).next }).map(Self::new)
}
pub fn attr(self, name: impl AsRef<str>) -> Option<String> {
let name = cstring(name).ok()?;
let value = unsafe { sys::switch_xml_attr(self.raw.as_ptr(), name.as_ptr()) };
if value.is_null() {
return None;
}
unsafe { CStr::from_ptr(value) }
.to_str()
.ok()
.map(ToOwned::to_owned)
}
}