use crate::Scf;
use crate::buf::scf_get_name;
use crate::error::HandleCreateError;
use crate::error::IterError;
use crate::error::IterErrorKind;
use crate::error::LibscfError;
use crate::error::ScfEntity;
use crate::error::ToEntityDescription;
use crate::scf::ScfObject;
use crate::utf8cstring::Utf8CString;
use std::marker::PhantomData;
mod sealed {
pub(crate) trait ScfIterable: crate::scf::ScfObjectType {
const ENTITY: crate::error::ScfEntity;
unsafe fn try_next(
iter: *mut libscf_sys::scf_iter_t,
uninitialized_item: *mut Self,
) -> libc::c_int;
}
pub(crate) trait ScfNamedIterable: ScfIterable {
unsafe fn get_name(
item: *const Self,
buf: *mut libc::c_char,
buf_len: usize,
) -> libc::ssize_t;
}
}
impl sealed::ScfIterable for libscf_sys::scf_value_t {
const ENTITY: ScfEntity = ScfEntity::Value;
unsafe fn try_next(
iter: *mut libscf_sys::scf_iter_t,
uninitialized_item: *mut Self,
) -> libc::c_int {
unsafe { libscf_sys::scf_iter_next_value(iter, uninitialized_item) }
}
}
impl sealed::ScfIterable for libscf_sys::scf_propertygroup_t {
const ENTITY: ScfEntity = ScfEntity::PropertyGroup;
unsafe fn try_next(
iter: *mut libscf_sys::scf_iter_t,
uninitialized_item: *mut Self,
) -> libc::c_int {
unsafe { libscf_sys::scf_iter_next_pg(iter, uninitialized_item) }
}
}
impl sealed::ScfNamedIterable for libscf_sys::scf_propertygroup_t {
unsafe fn get_name(
item: *const Self,
buf: *mut libc::c_char,
buf_len: usize,
) -> libc::ssize_t {
unsafe { libscf_sys::scf_pg_get_name(item, buf, buf_len) }
}
}
impl sealed::ScfIterable for libscf_sys::scf_property_t {
const ENTITY: ScfEntity = ScfEntity::Property;
unsafe fn try_next(
iter: *mut libscf_sys::scf_iter_t,
uninitialized_item: *mut Self,
) -> libc::c_int {
unsafe { libscf_sys::scf_iter_next_property(iter, uninitialized_item) }
}
}
impl sealed::ScfNamedIterable for libscf_sys::scf_property_t {
unsafe fn get_name(
item: *const Self,
buf: *mut libc::c_char,
buf_len: usize,
) -> libc::ssize_t {
unsafe { libscf_sys::scf_property_get_name(item, buf, buf_len) }
}
}
impl sealed::ScfIterable for libscf_sys::scf_instance_t {
const ENTITY: ScfEntity = ScfEntity::Instance;
unsafe fn try_next(
iter: *mut libscf_sys::scf_iter_t,
uninitialized_item: *mut Self,
) -> libc::c_int {
unsafe { libscf_sys::scf_iter_next_instance(iter, uninitialized_item) }
}
}
impl sealed::ScfNamedIterable for libscf_sys::scf_instance_t {
unsafe fn get_name(
item: *const Self,
buf: *mut libc::c_char,
buf_len: usize,
) -> libc::ssize_t {
unsafe { libscf_sys::scf_instance_get_name(item, buf, buf_len) }
}
}
impl sealed::ScfIterable for libscf_sys::scf_snapshot_t {
const ENTITY: ScfEntity = ScfEntity::Snapshot;
unsafe fn try_next(
iter: *mut libscf_sys::scf_iter_t,
uninitialized_item: *mut Self,
) -> libc::c_int {
unsafe { libscf_sys::scf_iter_next_snapshot(iter, uninitialized_item) }
}
}
impl sealed::ScfNamedIterable for libscf_sys::scf_snapshot_t {
unsafe fn get_name(
item: *const Self,
buf: *mut libc::c_char,
buf_len: usize,
) -> libc::ssize_t {
unsafe { libscf_sys::scf_snapshot_get_name(item, buf, buf_len) }
}
}
pub(crate) struct ScfUninitializedIter<'a> {
handle: ScfObject<'a, libscf_sys::scf_iter_t>,
}
impl<'a> ScfUninitializedIter<'a> {
pub(crate) fn new(scf: &'a Scf<'a>) -> Result<Self, HandleCreateError> {
Ok(Self { handle: scf.scf_iter_create()? })
}
pub(crate) unsafe fn init_property_values(
mut self,
property: *const libscf_sys::scf_property_t,
) -> Result<ScfIter<'a, libscf_sys::scf_value_t>, LibscfError> {
LibscfError::from_ret(unsafe {
libscf_sys::scf_iter_property_values(
self.handle.as_mut_ptr(),
property,
)
})?;
Ok(ScfIter { handle: self.handle, _inner: PhantomData })
}
pub(crate) unsafe fn init_service_instances(
mut self,
service: *const libscf_sys::scf_service_t,
) -> Result<ScfIter<'a, libscf_sys::scf_instance_t>, LibscfError> {
LibscfError::from_ret(unsafe {
libscf_sys::scf_iter_service_instances(
self.handle.as_mut_ptr(),
service,
)
})?;
Ok(ScfIter { handle: self.handle, _inner: PhantomData })
}
pub(crate) unsafe fn init_service_property_groups(
mut self,
service: *const libscf_sys::scf_service_t,
) -> Result<ScfIter<'a, libscf_sys::scf_propertygroup_t>, LibscfError> {
LibscfError::from_ret(unsafe {
libscf_sys::scf_iter_service_pgs(self.handle.as_mut_ptr(), service)
})?;
Ok(ScfIter { handle: self.handle, _inner: PhantomData })
}
pub(crate) unsafe fn init_instance_property_groups(
mut self,
instance: *const libscf_sys::scf_instance_t,
) -> Result<ScfIter<'a, libscf_sys::scf_propertygroup_t>, LibscfError> {
LibscfError::from_ret(unsafe {
libscf_sys::scf_iter_instance_pgs(
self.handle.as_mut_ptr(),
instance,
)
})?;
Ok(ScfIter { handle: self.handle, _inner: PhantomData })
}
pub(crate) unsafe fn init_instance_property_groups_composed(
mut self,
instance: *const libscf_sys::scf_instance_t,
snapshot: *const libscf_sys::scf_snapshot_t,
) -> Result<ScfIter<'a, libscf_sys::scf_propertygroup_t>, LibscfError> {
LibscfError::from_ret(unsafe {
libscf_sys::scf_iter_instance_pgs_composed(
self.handle.as_mut_ptr(),
instance,
snapshot,
)
})?;
Ok(ScfIter { handle: self.handle, _inner: PhantomData })
}
pub(crate) unsafe fn init_instance_snapshots(
mut self,
instance: *const libscf_sys::scf_instance_t,
) -> Result<ScfIter<'a, libscf_sys::scf_snapshot_t>, LibscfError> {
LibscfError::from_ret(unsafe {
libscf_sys::scf_iter_instance_snapshots(
self.handle.as_mut_ptr(),
instance,
)
})?;
Ok(ScfIter { handle: self.handle, _inner: PhantomData })
}
pub(crate) unsafe fn init_property_group_properties(
mut self,
pg: *const libscf_sys::scf_propertygroup_t,
) -> Result<ScfIter<'a, libscf_sys::scf_property_t>, LibscfError> {
LibscfError::from_ret(unsafe {
libscf_sys::scf_iter_pg_properties(self.handle.as_mut_ptr(), pg)
})?;
Ok(ScfIter { handle: self.handle, _inner: PhantomData })
}
}
pub(crate) struct ScfIter<'a, T> {
handle: ScfObject<'a, libscf_sys::scf_iter_t>,
_inner: PhantomData<fn() -> T>,
}
impl<'a, T: sealed::ScfIterable> ScfIter<'a, T> {
pub(crate) fn next_with_handle<P>(
&mut self,
parent: &P,
handle: &mut ScfObject<'a, T>,
) -> Option<Result<(), IterError>>
where
P: ToEntityDescription,
{
match unsafe {
T::try_next(self.handle.as_mut_ptr(), handle.as_mut_ptr())
} {
0 => None,
1 => Some(Ok(())),
_ => Some(Err(IterError::Iter {
entity: T::ENTITY,
parent: parent.to_entity_description(),
kind: IterErrorKind::GetNext(LibscfError::last()),
})),
}
}
}
impl<'a, T: sealed::ScfNamedIterable> ScfIter<'a, T> {
pub(crate) fn next_named<F, P>(
&mut self,
parent: &P,
make_handle: F,
) -> Option<Result<(Utf8CString, ScfObject<'a, T>), IterError>>
where
P: ToEntityDescription,
F: FnOnce() -> Result<ScfObject<'a, T>, HandleCreateError>,
{
let mut handle = match make_handle() {
Ok(handle) => handle,
Err(err) => return Some(Err(err.into())),
};
match self.next_with_handle(parent, &mut handle)? {
Ok(()) => (),
Err(err) => return Some(Err(err)),
}
let name = match scf_get_name(|buf, buf_len| unsafe {
T::get_name(handle.as_ptr(), buf, buf_len)
}) {
Ok(name) => name,
Err(err) => {
return Some(Err(IterError::Iter {
entity: T::ENTITY,
parent: parent.to_entity_description(),
kind: IterErrorKind::GetName(err),
}));
}
};
Some(Ok((name, handle)))
}
}