forked from mirrors/gstreamer-rs
Iterator: Add a wrapper implementing std's Iterator
Transposing the item type lets us be a std-compatible Iterator. The iterator is automatically resynced when resuming iteration after yielding Resync. This lets some combinators like `collect` and `find` work properly.
This commit is contained in:
parent
db61ec4a6b
commit
a30935ad1f
2 changed files with 127 additions and 1 deletions
|
@ -18,6 +18,7 @@ use gst_sys;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::iter;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
@ -180,6 +181,10 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn iter(self) -> StdIterator<T> {
|
||||||
|
StdIterator::new(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Iterator<T>
|
impl<T> Iterator<T>
|
||||||
|
@ -611,6 +616,65 @@ impl<T: StaticType> glib::translate::FromGlibPtrFull<*mut gst_sys::GstIterator>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct StdIterator<T> {
|
||||||
|
inner: Iterator<T>,
|
||||||
|
error: Option<IteratorError>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> StdIterator<T> {
|
||||||
|
fn new(inner: Iterator<T>) -> Self {
|
||||||
|
Self { inner, error: None }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: StaticType + 'static> Clone for StdIterator<T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: self.inner.clone(),
|
||||||
|
error: self.error,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> fmt::Debug for StdIterator<T> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
f.debug_struct("StdIterator")
|
||||||
|
.field("inner", &self.inner)
|
||||||
|
.field("error", &self.error)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> iter::Iterator for StdIterator<T>
|
||||||
|
where
|
||||||
|
for<'a> T: FromValueOptional<'a> + 'static,
|
||||||
|
{
|
||||||
|
type Item = Result<T, IteratorError>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
match self.error {
|
||||||
|
// Fuse the iterator after returning IteratorError::Error
|
||||||
|
Some(IteratorError::Error) => return None,
|
||||||
|
|
||||||
|
// The iterator needs a resync
|
||||||
|
Some(IteratorError::Resync) => {
|
||||||
|
self.inner.resync();
|
||||||
|
self.error = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = self.inner.next();
|
||||||
|
|
||||||
|
if let Err(err) = &res {
|
||||||
|
self.error = Some(*err);
|
||||||
|
}
|
||||||
|
|
||||||
|
res.transpose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -685,4 +749,66 @@ mod tests {
|
||||||
});
|
});
|
||||||
assert_eq!(res.unwrap(), 6);
|
assert_eq!(res.unwrap(), 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_std() {
|
||||||
|
let mut it = Iterator::from_vec(vec![1i32, 2, 3]).iter();
|
||||||
|
assert_eq!(it.next(), Some(Ok(1)));
|
||||||
|
assert_eq!(it.next(), Some(Ok(2)));
|
||||||
|
assert_eq!(it.next(), Some(Ok(3)));
|
||||||
|
assert_eq!(it.next(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_std_resync_collect() {
|
||||||
|
use prelude::*;
|
||||||
|
use std::collections::BTreeSet;
|
||||||
|
|
||||||
|
::init().unwrap();
|
||||||
|
|
||||||
|
let bin = ::Bin::new(None);
|
||||||
|
let id1 = ::ElementFactory::make("identity", None).unwrap();
|
||||||
|
let id2 = ::ElementFactory::make("identity", None).unwrap();
|
||||||
|
|
||||||
|
bin.add(&id1).unwrap();
|
||||||
|
|
||||||
|
let mut it = bin.iterate_elements().iter();
|
||||||
|
assert_eq!(it.next().unwrap().unwrap(), id1);
|
||||||
|
|
||||||
|
bin.add(&id2).unwrap();
|
||||||
|
|
||||||
|
let res = it.by_ref().collect::<Result<Vec<_>, _>>().unwrap_err();
|
||||||
|
assert_eq!(res, IteratorError::Resync);
|
||||||
|
|
||||||
|
let mut elems = BTreeSet::new();
|
||||||
|
elems.insert(id1);
|
||||||
|
elems.insert(id2);
|
||||||
|
|
||||||
|
let res = it.by_ref().collect::<Result<BTreeSet<_>, _>>().unwrap();
|
||||||
|
assert_eq!(res, elems);
|
||||||
|
|
||||||
|
let res = it.collect::<Result<Vec<_>, _>>().unwrap();
|
||||||
|
assert!(res.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_std_resync_find() {
|
||||||
|
use prelude::*;
|
||||||
|
|
||||||
|
::init().unwrap();
|
||||||
|
|
||||||
|
let bin = ::Bin::new(None);
|
||||||
|
let id1 = ::ElementFactory::make("identity", None).unwrap();
|
||||||
|
let id2 = ::ElementFactory::make("identity", None).unwrap();
|
||||||
|
|
||||||
|
bin.add(&id1).unwrap();
|
||||||
|
|
||||||
|
let mut it = bin.iterate_elements().iter();
|
||||||
|
assert_eq!(it.next().unwrap().unwrap(), id1);
|
||||||
|
|
||||||
|
bin.add(&id2).unwrap();
|
||||||
|
|
||||||
|
let res = it.find(|x| x.as_ref() == Ok(&id1));
|
||||||
|
assert_eq!(res.unwrap().unwrap(), id1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -221,7 +221,7 @@ cfg_if! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use self::iterator::{Iterator, IteratorError, IteratorImpl};
|
pub use self::iterator::{Iterator, IteratorError, IteratorImpl, StdIterator};
|
||||||
#[cfg(any(feature = "futures", feature = "dox"))]
|
#[cfg(any(feature = "futures", feature = "dox"))]
|
||||||
pub use bus::BusStream;
|
pub use bus::BusStream;
|
||||||
pub use child_proxy::ChildProxyExtManual;
|
pub use child_proxy::ChildProxyExtManual;
|
||||||
|
|
Loading…
Reference in a new issue