Implement std::iter::Iterator<Item=Result<glib::Value, IteratorError> for gst::Iterator

This commit is contained in:
Sebastian Dröge 2017-09-17 14:39:17 +03:00
parent 8306e5cf72
commit f7bce553cd
5 changed files with 92 additions and 118 deletions

View file

@ -55,7 +55,6 @@ generate = [
"Gst.SegmentFlags", "Gst.SegmentFlags",
"Gst.PadMode", "Gst.PadMode",
"Gst.SchedulingFlags", "Gst.SchedulingFlags",
"Gst.IteratorResult",
"Gst.ChildProxy", "Gst.ChildProxy",
"Gst.Preset", "Gst.Preset",
"Gst.TagSetter", "Gst.TagSetter",

View file

@ -836,69 +836,6 @@ impl SetValue for Format {
} }
} }
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum IteratorResult {
Done,
Ok,
Resync,
Error,
#[doc(hidden)]
__Unknown(i32),
}
#[doc(hidden)]
impl ToGlib for IteratorResult {
type GlibType = ffi::GstIteratorResult;
fn to_glib(&self) -> ffi::GstIteratorResult {
match *self {
IteratorResult::Done => ffi::GST_ITERATOR_DONE,
IteratorResult::Ok => ffi::GST_ITERATOR_OK,
IteratorResult::Resync => ffi::GST_ITERATOR_RESYNC,
IteratorResult::Error => ffi::GST_ITERATOR_ERROR,
IteratorResult::__Unknown(value) => unsafe{std::mem::transmute(value)}
}
}
}
#[doc(hidden)]
impl FromGlib<ffi::GstIteratorResult> for IteratorResult {
fn from_glib(value: ffi::GstIteratorResult) -> Self {
skip_assert_initialized!();
match value as i32 {
0 => IteratorResult::Done,
1 => IteratorResult::Ok,
2 => IteratorResult::Resync,
3 => IteratorResult::Error,
value => IteratorResult::__Unknown(value),
}
}
}
impl StaticType for IteratorResult {
fn static_type() -> Type {
unsafe { from_glib(ffi::gst_iterator_result_get_type()) }
}
}
impl<'a> FromValueOptional<'a> for IteratorResult {
unsafe fn from_value_optional(value: &Value) -> Option<Self> {
Some(FromValue::from_value(value))
}
}
impl<'a> FromValue<'a> for IteratorResult {
unsafe fn from_value(value: &Value) -> Self {
from_glib(std::mem::transmute::<i32, ffi::GstIteratorResult>(gobject_ffi::g_value_get_enum(value.to_glib_none().0)))
}
}
impl SetValue for IteratorResult {
unsafe fn set_value(value: &mut Value, this: &Self) {
gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, this.to_glib() as i32)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum LibraryError { pub enum LibraryError {
Failed, Failed,

View file

@ -108,7 +108,6 @@ pub use self::enums::DebugLevel;
pub use self::enums::EventType; pub use self::enums::EventType;
pub use self::enums::FlowReturn; pub use self::enums::FlowReturn;
pub use self::enums::Format; pub use self::enums::Format;
pub use self::enums::IteratorResult;
pub use self::enums::LibraryError; pub use self::enums::LibraryError;
pub use self::enums::PadDirection; pub use self::enums::PadDirection;
pub use self::enums::PadLinkReturn; pub use self::enums::PadLinkReturn;

View file

@ -10,9 +10,15 @@ use std::mem;
use std::ptr; use std::ptr;
use glib; use glib;
use glib::Value; use glib::Value;
use IteratorResult;
use std::sync::Arc; use std::sync::Arc;
use std::ffi::CString; use std::ffi::CString;
use std::iter::Iterator as StdIterator;
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum IteratorError {
Resync,
Error,
}
glib_wrapper! { glib_wrapper! {
pub struct Iterator(Boxed<ffi::GstIterator>); pub struct Iterator(Boxed<ffi::GstIterator>);
@ -25,22 +31,6 @@ glib_wrapper! {
} }
impl Iterator { impl Iterator {
#[cfg_attr(feature = "cargo-clippy", allow(should_implement_trait))]
pub fn next(&mut self) -> Result<Value, IteratorResult> {
unsafe {
let mut value = Value::uninitialized();
let res = from_glib(ffi::gst_iterator_next(
self.to_glib_none_mut().0,
value.to_glib_none_mut().0,
));
if res == IteratorResult::Ok {
Ok(value)
} else {
Err(res)
}
}
}
pub fn resync(&mut self) { pub fn resync(&mut self) {
unsafe { unsafe {
ffi::gst_iterator_resync(self.to_glib_none_mut().0); ffi::gst_iterator_resync(self.to_glib_none_mut().0);
@ -74,7 +64,7 @@ impl Iterator {
} }
} }
pub fn find<F>(&mut self, func: F) -> Option<glib::Value> pub fn find_simple<F>(&mut self, func: F) -> Option<glib::Value>
where where
F: FnMut(&glib::Value) -> bool, F: FnMut(&glib::Value) -> bool,
{ {
@ -99,7 +89,7 @@ impl Iterator {
} }
} }
pub fn foreach<F>(&mut self, func: F) -> IteratorResult pub fn foreach<F>(&mut self, func: F) -> Result<(), IteratorError>
where where
F: FnMut(&glib::Value), F: FnMut(&glib::Value),
{ {
@ -108,15 +98,21 @@ impl Iterator {
let func_obj: &mut (FnMut(&glib::Value)) = &mut func; let func_obj: &mut (FnMut(&glib::Value)) = &mut func;
let func_ptr = &func_obj as *const &mut (FnMut(&glib::Value)) as gpointer; let func_ptr = &func_obj as *const &mut (FnMut(&glib::Value)) as gpointer;
from_glib(ffi::gst_iterator_foreach( let res = ffi::gst_iterator_foreach(
self.to_glib_none_mut().0, self.to_glib_none_mut().0,
Some(foreach_trampoline), Some(foreach_trampoline),
func_ptr, func_ptr,
)) );
match res {
ffi::GST_ITERATOR_OK | ffi::GST_ITERATOR_DONE => Ok(()),
ffi::GST_ITERATOR_RESYNC => Err(IteratorError::Resync),
ffi::GST_ITERATOR_ERROR => Err(IteratorError::Error),
}
} }
} }
pub fn fold<F, T>(&mut self, init: T, func: F) -> Result<T, IteratorResult> pub fn fold_with_early_exit<F, T>(&mut self, init: T, func: F) -> Result<T, IteratorError>
where where
F: FnMut(T, &glib::Value) -> Result<T, T>, F: FnMut(T, &glib::Value) -> Result<T, T>,
{ {
@ -134,18 +130,19 @@ impl Iterator {
&mut accum as *mut _ as gpointer, &mut accum as *mut _ as gpointer,
); );
let res = from_glib(ffi::gst_iterator_fold( let res = ffi::gst_iterator_fold(
self.to_glib_none_mut().0, self.to_glib_none_mut().0,
Some(fold_trampoline::<T>), Some(fold_trampoline::<T>),
ret.to_glib_none_mut().0, ret.to_glib_none_mut().0,
func_ptr, func_ptr,
)); );
gobject_ffi::g_value_unset(ret.to_glib_none_mut().0); gobject_ffi::g_value_unset(ret.to_glib_none_mut().0);
match res { match res {
IteratorResult::Ok | IteratorResult::Done => Ok(accum.unwrap()), ffi::GST_ITERATOR_OK | ffi::GST_ITERATOR_DONE => Ok(accum.unwrap()),
_ => Err(res), ffi::GST_ITERATOR_RESYNC => Err(IteratorError::Resync),
ffi::GST_ITERATOR_ERROR => Err(IteratorError::Error),
} }
} }
} }
@ -182,6 +179,23 @@ impl Iterator {
} }
} }
impl StdIterator for Iterator {
type Item = Result<Value, IteratorError>;
fn next(&mut self) -> Option<Result<Value, IteratorError>> {
unsafe {
let mut value = Value::uninitialized();
let res = ffi::gst_iterator_next(self.to_glib_none_mut().0, value.to_glib_none_mut().0);
match res {
ffi::GST_ITERATOR_OK => Some(Ok(value)),
ffi::GST_ITERATOR_DONE => None,
ffi::GST_ITERATOR_RESYNC => Some(Err(IteratorError::Resync)),
ffi::GST_ITERATOR_ERROR => Some(Err(IteratorError::Error)),
}
}
}
}
#[repr(C)] #[repr(C)]
struct RsIterator<I: IteratorImpl> { struct RsIterator<I: IteratorImpl> {
iter: ffi::GstIterator, iter: ffi::GstIterator,
@ -190,7 +204,7 @@ struct RsIterator<I: IteratorImpl> {
pub trait IteratorImpl: Clone + Send + 'static { pub trait IteratorImpl: Clone + Send + 'static {
fn item_type() -> glib::Type; fn item_type() -> glib::Type;
fn next(&mut self) -> Result<glib::Value, IteratorResult>; fn next(&mut self) -> Option<Result<glib::Value, IteratorError>>;
fn resync(&mut self); fn resync(&mut self);
} }
@ -218,15 +232,16 @@ unsafe extern "C" fn rs_iterator_next<I: IteratorImpl>(
callback_guard!(); callback_guard!();
let it = it as *mut RsIterator<I>; let it = it as *mut RsIterator<I>;
match (*it).imp.as_mut().map(|imp| imp.next()).unwrap() { match (*it).imp.as_mut().map(|imp| imp.next()).unwrap() {
Ok(value) => { Some(Ok(value)) => {
ptr::write(result, ptr::read(value.to_glib_none().0)); ptr::write(result, ptr::read(value.to_glib_none().0));
mem::forget(value); mem::forget(value);
ffi::GST_ITERATOR_OK ffi::GST_ITERATOR_OK
} }
Err(res) => { None => ffi::GST_ITERATOR_DONE,
assert_ne!(res, IteratorResult::Ok); Some(Err(res)) => match res {
res.to_glib() IteratorError::Resync => ffi::GST_ITERATOR_RESYNC,
} IteratorError::Error => ffi::GST_ITERATOR_ERROR,
},
} }
} }
@ -257,14 +272,14 @@ impl<T: glib::StaticType + glib::value::ToValue + Clone + Send + 'static> Iterat
T::static_type() T::static_type()
} }
fn next(&mut self) -> Result<glib::Value, IteratorResult> { fn next(&mut self) -> Option<Result<glib::Value, IteratorError>> {
if self.pos < self.items.len() { if self.pos < self.items.len() {
let res = Ok(self.items[self.pos].clone().to_value()); let res = Ok(self.items[self.pos].clone().to_value());
self.pos += 1; self.pos += 1;
return res; return Some(res);
} }
Err(IteratorResult::Done) None
} }
fn resync(&mut self) { fn resync(&mut self) {
@ -401,14 +416,26 @@ mod tests {
let vec = vec![1i32, 2, 3]; let vec = vec![1i32, 2, 3];
let mut it = Iterator::from_vec(vec); let mut it = Iterator::from_vec(vec);
let val = it.next().unwrap();
assert_eq!(val.unwrap().get::<i32>().unwrap(), 1);
let val = it.next().unwrap();
assert_eq!(val.unwrap().get::<i32>().unwrap(), 2);
let val = it.next().unwrap();
assert_eq!(val.unwrap().get::<i32>().unwrap(), 3);
assert!(it.next().is_none());
let val = it.next().unwrap(); let vec = vec![1i32, 2, 3];
assert_eq!(val.get::<i32>().unwrap(), 1); let it = Iterator::from_vec(vec);
let val = it.next().unwrap(); let vals: Vec<_> = it.map(|v| v.unwrap().get::<i32>().unwrap()).collect();
assert_eq!(val.get::<i32>().unwrap(), 2); assert_eq!(vals, [1, 2, 3]);
let val = it.next().unwrap();
assert_eq!(val.get::<i32>().unwrap(), 3); let vec = vec![1i32, 2, 3];
assert_eq!(it.next().unwrap_err(), IteratorResult::Done); let it = Iterator::from_vec(vec);
let mut vals = Vec::new();
for v in it {
vals.push(v.unwrap().get::<i32>().unwrap());
}
assert_eq!(vals, [1, 2, 3]);
} }
#[test] #[test]
@ -416,22 +443,25 @@ mod tests {
::init().unwrap(); ::init().unwrap();
let vec = vec![1i32, 2, 3]; let vec = vec![1i32, 2, 3];
let mut it = Iterator::from_vec(vec).filter(|val| val.get::<i32>().unwrap() % 2 == 1); let it = Iterator::from_vec(vec).filter(|val| val.get::<i32>().unwrap() % 2 == 1);
let vals: Vec<_> = it.map(|v| v.unwrap().get::<i32>().unwrap()).collect();
let val = it.next().unwrap(); assert_eq!(vals, [1, 3]);
assert_eq!(val.get::<i32>().unwrap(), 1);
let val = it.next().unwrap();
assert_eq!(val.get::<i32>().unwrap(), 3);
assert_eq!(it.next().unwrap_err(), IteratorResult::Done);
} }
#[test] #[test]
fn test_find() { fn test_find() {
::init().unwrap(); ::init().unwrap();
// Our find
let vec = vec![1i32, 2, 3]; let vec = vec![1i32, 2, 3];
let val = Iterator::from_vec(vec).find(|val| val.get::<i32>().unwrap() == 2); let val = Iterator::from_vec(vec).find_simple(|val| val.get::<i32>().unwrap() == 2);
assert_eq!(val.unwrap().get::<i32>().unwrap(), 2); assert_eq!(val.unwrap().get::<i32>().unwrap(), 2);
// Find from std::iter::Iterator
let vec = vec![1i32, 2, 3];
let val =
Iterator::from_vec(vec).find(|val| val.as_ref().unwrap().get::<i32>().unwrap() == 2);
assert_eq!(val.unwrap().unwrap().get::<i32>().unwrap(), 2);
} }
#[test] #[test]
@ -441,7 +471,7 @@ mod tests {
let vec = vec![1i32, 2, 3]; let vec = vec![1i32, 2, 3];
let mut sum = 0; let mut sum = 0;
let res = Iterator::from_vec(vec).foreach(|val| sum += val.get::<i32>().unwrap()); let res = Iterator::from_vec(vec).foreach(|val| sum += val.get::<i32>().unwrap());
assert_eq!(res, IteratorResult::Done); assert_eq!(res, Ok(()));
assert_eq!(sum, 6); assert_eq!(sum, 6);
} }
@ -449,11 +479,20 @@ mod tests {
fn test_fold() { fn test_fold() {
::init().unwrap(); ::init().unwrap();
// Our fold
let vec = vec![1i32, 2, 3]; let vec = vec![1i32, 2, 3];
let res = Iterator::from_vec(vec).fold(0, |mut sum, val| { let res = Iterator::from_vec(vec).fold_with_early_exit(0, |mut sum, val| {
sum += val.get::<i32>().unwrap(); sum += val.get::<i32>().unwrap();
Ok(sum) Ok(sum)
}); });
assert_eq!(res.unwrap(), 6); assert_eq!(res.unwrap(), 6);
// Fold from std::iter::Iterator
let vec = vec![1i32, 2, 3];
let res = Iterator::from_vec(vec).fold(0, |mut sum, val| {
sum += val.unwrap().get::<i32>().unwrap();
sum
});
assert_eq!(res, 6);
} }
} }

View file

@ -104,7 +104,7 @@ pub use pad::{PadExtManual, PadProbeData, PadProbeId, PadProbeInfo, PAD_PROBE_ID
pub use gobject::GObjectExtManualGst; pub use gobject::GObjectExtManualGst;
pub use child_proxy::ChildProxyExtManual; pub use child_proxy::ChildProxyExtManual;
pub use tag_setter::TagSetterExtManual; pub use tag_setter::TagSetterExtManual;
pub use self::iterator::Iterator; pub use self::iterator::{Iterator, IteratorError};
pub use device_provider::DeviceProviderExtManual; pub use device_provider::DeviceProviderExtManual;
pub use parse_context::ParseContext; pub use parse_context::ParseContext;
#[cfg(feature = "futures")] #[cfg(feature = "futures")]