use crate::xmp::{PropFlags, Xmp};
use crate::xmpstring::XmpString;
use std::ffi::CString;
bitflags! {
#[derive(Clone, Copy, Default, Debug, Eq, Hash, PartialEq)]
pub struct IterFlags: u32 {
const NONE = 0;
const CLASS_MASK = 0x00FFu32;
const PROPERTIES = 0x0000u32;
const ALIASES = 0x0001u32;
const NAMESPACES = 0x0002u32;
const JUST_CHILDREN = 0x0100u32;
const JUST_LEAF_NODES = 0x0200u32;
const JUST_LEAF_NAME = 0x0400u32;
const INCLUDE_ALIASES = 0x0800u32;
const OMIT_QUALIFIERS = 0x1000u32;
}
}
bitflags! {
#[derive(Clone, Copy, Default, Debug, Eq, Hash, PartialEq)]
pub struct IterSkipFlags: u32 {
const NONE = 0;
const SUBTREE = 0x0001u32;
const SIBLINGS = 0x0002u32;
}
}
pub struct XmpIterator(*mut c::XmpIterator);
#[derive(Debug, Default, Eq, PartialEq)]
pub struct IteratorValue {
pub schema: XmpString,
pub name: XmpString,
pub value: XmpString,
pub option: PropFlags,
}
impl IteratorValue {
pub fn new() -> IteratorValue {
IteratorValue::default()
}
}
impl XmpIterator {
pub fn new<S, N>(xmp: &Xmp, schema: S, name: N, propsbits: IterFlags) -> XmpIterator
where
S: AsRef<[u8]>,
N: AsRef<[u8]>,
{
let s_schema = CString::new(schema.as_ref()).unwrap();
let s_name = CString::new(name.as_ref()).unwrap();
XmpIterator(unsafe {
c::xmp_iterator_new(
xmp.as_ptr(),
s_schema.as_ptr(),
s_name.as_ptr(),
propsbits.bits(),
)
})
}
pub fn is_null(&self) -> bool {
self.0.is_null()
}
pub fn as_ptr(&self) -> *mut c::XmpIterator {
self.0
}
pub fn skip(&mut self, option: IterSkipFlags) -> bool {
if self.is_null() {
return false;
}
unsafe { c::xmp_iterator_skip(self.0, option.bits()) }
}
}
impl Iterator for XmpIterator {
type Item = IteratorValue;
fn next(&mut self) -> Option<Self::Item> {
let mut value = IteratorValue::new();
let mut raw_option: u32 = 0;
if unsafe {
c::xmp_iterator_next(
self.0,
value.schema.as_mut_ptr(),
value.name.as_mut_ptr(),
value.value.as_mut_ptr(),
&mut raw_option,
)
} {
value.option = PropFlags::from_bits(raw_option).unwrap_or_default();
Some(value)
} else {
None
}
}
}
impl Drop for XmpIterator {
fn drop(&mut self) {
if !self.is_null() {
unsafe { c::xmp_iterator_free(self.0) };
}
}
}
#[cfg(test)]
#[test]
fn iterator_works() {
let inited = super::init();
assert!(inited);
let mut xmp = Xmp::new();
let mut iter = XmpIterator::new(
&mut xmp,
"http://ns.adobe.com/xap/1.0/",
"keyword",
IterFlags::from_bits(0).unwrap_or_default(),
);
assert_eq!(iter.next(), None);
}