use std::ffi::CStr;
use crate::{
Result,
error::maybe_err,
librados::{rados_getxattrs_end, rados_getxattrs_next, rados_xattrs_iter_t},
};
pub struct ExtendedAttributes {
inner: rados_xattrs_iter_t,
}
unsafe impl Send for ExtendedAttributes {}
impl ExtendedAttributes {
pub(crate) unsafe fn new(inner: rados_xattrs_iter_t) -> Self {
Self { inner }
}
pub fn try_next<'a>(&'a mut self) -> Result<Option<(&'a CStr, &'a [u8])>> {
let mut name = std::ptr::null();
let mut val = std::ptr::null();
let mut val_len = 0;
maybe_err(unsafe { rados_getxattrs_next(self.inner, &mut name, &mut val, &mut val_len) })?;
if name == std::ptr::null() && val == std::ptr::null() && val_len == 0 {
Ok(None)
}
else if name != std::ptr::null() && val == std::ptr::null() && val_len == 0 {
let name = unsafe { CStr::from_ptr(name) };
let val = unsafe { core::slice::from_raw_parts(std::ptr::dangling(), 0) };
Ok(Some((name, val)))
} else {
assert!(!name.is_null());
assert!(!val.is_null());
let name = unsafe { CStr::from_ptr(name) };
let val = unsafe { core::slice::from_raw_parts(val as *const u8, val_len) };
Ok(Some((name, val)))
}
}
}
impl Iterator for ExtendedAttributes {
type Item = Result<(String, Vec<u8>)>;
fn next(&mut self) -> Option<Self::Item> {
self.try_next()
.map(|v| v.map(|(k, v)| (k.to_string_lossy().into(), v.to_vec())))
.transpose()
}
}
impl Drop for ExtendedAttributes {
fn drop(&mut self) {
unsafe { rados_getxattrs_end(self.inner) }
}
}