use std::ffi::{CStr, CString};
use std::marker::PhantomData;
use std::os::raw::c_char;
use crate::control::Control;
use crate::error::{ClingoError, Error, check};
pub struct Configuration<'a> {
ptr: *mut clingo_sys::clingo_configuration_t,
key: clingo_sys::clingo_id_t,
_lifetime: PhantomData<&'a mut Control>,
}
impl<'a> Configuration<'a> {
pub(crate) unsafe fn new(
ptr: *mut clingo_sys::clingo_configuration_t,
key: clingo_sys::clingo_id_t,
) -> Self {
Configuration {
ptr,
key,
_lifetime: PhantomData,
}
}
pub fn map_at(&self, name: &str) -> Result<Configuration<'a>, Error> {
let c_name = CString::new(name)?;
let mut subkey: clingo_sys::clingo_id_t = 0;
check(unsafe {
clingo_sys::clingo_configuration_map_at(
self.ptr,
self.key,
c_name.as_ptr(),
&mut subkey,
)
})?;
Ok(Configuration {
ptr: self.ptr,
key: subkey,
_lifetime: self._lifetime,
})
}
pub fn array_at(&self, index: usize) -> Result<Configuration<'a>, ClingoError> {
let mut subkey: clingo_sys::clingo_id_t = 0;
check(unsafe {
clingo_sys::clingo_configuration_array_at(self.ptr, self.key, index, &mut subkey)
})?;
Ok(Configuration {
ptr: self.ptr,
key: subkey,
_lifetime: self._lifetime,
})
}
pub fn value(&self) -> Result<Option<String>, ClingoError> {
let mut assigned = false;
check(unsafe {
clingo_sys::clingo_configuration_value_is_assigned(self.ptr, self.key, &mut assigned)
})?;
if !assigned {
return Ok(None);
}
let mut size: usize = 0;
check(unsafe {
clingo_sys::clingo_configuration_value_get_size(self.ptr, self.key, &mut size)
})?;
let mut buf = vec![0u8; size];
check(unsafe {
clingo_sys::clingo_configuration_value_get(
self.ptr,
self.key,
buf.as_mut_ptr() as *mut c_char,
size,
)
})?;
buf.pop(); Ok(Some(String::from_utf8_lossy(&buf).into_owned()))
}
pub fn set_value(&mut self, value: &str) -> Result<(), Error> {
let c_value = CString::new(value)?;
check(unsafe {
clingo_sys::clingo_configuration_value_set(self.ptr, self.key, c_value.as_ptr())
})?;
Ok(())
}
pub fn get(&self, path: &str) -> Result<Option<String>, Error> {
let entry = self.walk(path)?;
Ok(entry.value()?)
}
pub fn set(&mut self, path: &str, value: &str) -> Result<(), Error> {
let mut entry = self.walk(path)?;
entry.set_value(value)
}
pub fn description(&self) -> Result<&str, ClingoError> {
let mut ptr: *const c_char = std::ptr::null();
check(unsafe {
clingo_sys::clingo_configuration_description(self.ptr, self.key, &mut ptr)
})?;
Ok(unsafe { CStr::from_ptr(ptr) }
.to_str()
.expect("clingo config description not UTF-8"))
}
fn walk(&self, path: &str) -> Result<Configuration<'a>, Error> {
let mut current = Configuration {
ptr: self.ptr,
key: self.key,
_lifetime: self._lifetime,
};
for segment in path.split('.') {
if let Ok(index) = segment.parse::<usize>() {
current = current.array_at(index)?;
} else {
current = current.map_at(segment)?;
}
}
Ok(current)
}
}