gstreamer-rs/gstreamer/src/iterator.rs
Bilal Elmoussaoui 4ebec84f5e Adapt to no longer renamed ffi crates
Allows us to set all the crates in the main workspace file, so changing
their versions or branch is much simpler and reduce the amount of noise
in the diff

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1450>
2024-06-02 11:20:55 +02:00

850 lines
23 KiB
Rust

// Take a look at the license at the top of the repository in the LICENSE file.
use std::{any::Any, fmt, iter, marker::PhantomData, mem, ptr, sync::Arc};
use crate::ffi;
use glib::{
ffi::{gconstpointer, gpointer},
prelude::*,
translate::*,
value::{FromValue, ToValue},
Value,
};
use thiserror::Error;
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Error)]
pub enum IteratorError {
#[error("Resync")]
Resync,
#[error("Error")]
Error,
}
// Implemented manually so that we can use generics for the item
pub struct Iterator<T> {
iter: ptr::NonNull<ffi::GstIterator>,
phantom: PhantomData<T>,
}
impl<T> Iterator<T>
where
for<'a> T: FromValue<'a> + 'static,
{
#[allow(clippy::should_implement_trait)]
#[doc(alias = "gst_iterator_next")]
pub fn next(&mut self) -> Result<Option<T>, 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);
#[allow(clippy::wildcard_in_or_patterns)]
match res {
ffi::GST_ITERATOR_OK => match value.get::<T>() {
Ok(value) => Ok(Some(value)),
Err(_) => Err(IteratorError::Error),
},
ffi::GST_ITERATOR_DONE => Ok(None),
ffi::GST_ITERATOR_RESYNC => Err(IteratorError::Resync),
ffi::GST_ITERATOR_ERROR | _ => Err(IteratorError::Error),
}
}
}
#[doc(alias = "gst_iterator_resync")]
pub fn resync(&mut self) {
unsafe {
ffi::gst_iterator_resync(self.to_glib_none_mut().0);
}
}
#[doc(alias = "gst_iterator_filter")]
#[must_use]
pub fn filter<F>(self, func: F) -> Self
where
F: Fn(T) -> bool + Send + Sync + 'static,
T: StaticType,
{
unsafe {
let func_box: Box<dyn Any + Send + Sync + 'static> = Box::new(func);
let mut closure_value = glib::Value::from_type_unchecked(filter_boxed_get_type());
glib::gobject_ffi::g_value_take_boxed(
closure_value.to_glib_none_mut().0,
Arc::into_raw(Arc::new(func_box)) as gpointer,
);
from_glib_full(ffi::gst_iterator_filter(
self.into_glib_ptr(),
Some(filter_trampoline::<T, F>),
closure_value.to_glib_none().0,
))
}
}
#[doc(alias = "gst_iterator_find_custom")]
pub fn find<F>(&mut self, func: F) -> Option<T>
where
F: FnMut(T) -> bool,
{
unsafe {
let mut elem = glib::Value::uninitialized();
let mut func = func;
let func_ptr = &mut func as *mut F as gpointer;
let res = from_glib(ffi::gst_iterator_find_custom(
self.to_glib_none_mut().0,
Some(find_trampoline::<T, F>),
elem.to_glib_none_mut().0,
func_ptr,
));
if res {
Some(elem.get::<T>().expect("Iterator::find"))
} else {
None
}
}
}
#[doc(alias = "gst_iterator_foreach")]
pub fn foreach<F>(&mut self, func: F) -> Result<(), IteratorError>
where
F: FnMut(T),
{
unsafe {
let mut func = func;
let func_ptr = &mut func as *mut F as gpointer;
let res = ffi::gst_iterator_foreach(
self.to_glib_none_mut().0,
Some(foreach_trampoline::<T, F>),
func_ptr,
);
#[allow(clippy::wildcard_in_or_patterns)]
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),
}
}
}
#[doc(alias = "gst_iterator_fold")]
pub fn fold<F, U>(&mut self, init: U, func: F) -> Result<U, IteratorError>
where
F: FnMut(U, T) -> Result<U, U>,
{
unsafe {
let mut func = func;
let func_ptr = &mut func as *mut F as gpointer;
let mut accum = Some(init);
let mut ret = glib::Value::from_type_unchecked(glib::Type::POINTER);
glib::gobject_ffi::g_value_set_pointer(
ret.to_glib_none_mut().0,
&mut accum as *mut _ as gpointer,
);
let res = ffi::gst_iterator_fold(
self.to_glib_none_mut().0,
Some(fold_trampoline::<T, U, F>),
ret.to_glib_none_mut().0,
func_ptr,
);
#[allow(clippy::wildcard_in_or_patterns)]
match res {
ffi::GST_ITERATOR_OK | ffi::GST_ITERATOR_DONE => Ok(accum.unwrap()),
ffi::GST_ITERATOR_RESYNC => Err(IteratorError::Resync),
ffi::GST_ITERATOR_ERROR | _ => Err(IteratorError::Error),
}
}
}
}
impl<T> Iterator<T>
where
for<'a> T: FromValue<'a> + StaticType + ToValue + Send + 'static,
{
#[doc(alias = "gst_iterator_new")]
pub fn new<I: IteratorImpl<T>>(imp: I) -> Self {
assert_initialized_main_thread!();
static DUMMY_COOKIE: u32 = 0;
unsafe {
let it = ffi::gst_iterator_new(
mem::size_of::<RsIterator<T, I>>() as u32,
T::static_type().into_glib(),
ptr::null_mut(),
&DUMMY_COOKIE as *const _ as *mut _,
Some(rs_iterator_copy::<T, I>),
Some(rs_iterator_next::<T, I>),
None,
Some(rs_iterator_resync::<T, I>),
Some(rs_iterator_free::<T, I>),
);
{
let it = it as *mut RsIterator<T, I>;
ptr::write(&mut (*it).imp, imp);
}
from_glib_full(it)
}
}
}
impl<T> Iterator<T>
where
for<'a> T: FromValue<'a> + StaticType + ToValue + Clone + Send + 'static,
{
pub fn from_vec(items: Vec<T>) -> Self {
skip_assert_initialized!();
Self::new(VecIteratorImpl::new(items))
}
}
impl<T: 'static> IntoGlibPtr<*mut ffi::GstIterator> for Iterator<T> {
#[inline]
unsafe fn into_glib_ptr(self) -> *mut ffi::GstIterator {
let s = mem::ManuallyDrop::new(self);
let it = s.to_glib_none().0;
it as *mut _
}
}
#[repr(C)]
struct RsIterator<T, I: IteratorImpl<T>>
where
for<'a> T: FromValue<'a> + StaticType + ToValue + Send + 'static,
{
iter: ffi::GstIterator,
imp: I,
phantom: PhantomData<T>,
}
pub trait IteratorImpl<T>: Clone + Send + 'static
where
for<'a> T: FromValue<'a> + StaticType + ToValue + Send + 'static,
{
fn next(&mut self) -> Option<Result<T, IteratorError>>;
fn resync(&mut self);
}
unsafe extern "C" fn rs_iterator_copy<T, I: IteratorImpl<T>>(
it: *const ffi::GstIterator,
copy: *mut ffi::GstIterator,
) where
for<'a> T: FromValue<'a> + StaticType + ToValue + Send + 'static,
{
let it = it as *const RsIterator<T, I>;
let copy = copy as *mut RsIterator<T, I>;
ptr::write(&mut (*copy).imp, (*it).imp.clone());
}
unsafe extern "C" fn rs_iterator_free<T, I: IteratorImpl<T>>(it: *mut ffi::GstIterator)
where
for<'a> T: FromValue<'a> + StaticType + ToValue + Send + 'static,
{
let it = it as *mut RsIterator<T, I>;
ptr::drop_in_place(&mut (*it).imp);
}
unsafe extern "C" fn rs_iterator_next<T, I: IteratorImpl<T>>(
it: *mut ffi::GstIterator,
result: *mut glib::gobject_ffi::GValue,
) -> ffi::GstIteratorResult
where
for<'a> T: FromValue<'a> + StaticType + ToValue + Send + 'static,
{
let it = it as *mut RsIterator<T, I>;
match (*it).imp.next() {
Some(Ok(value)) => {
let value = value.to_value();
ptr::write(result, value.into_raw());
ffi::GST_ITERATOR_OK
}
None => ffi::GST_ITERATOR_DONE,
Some(Err(res)) => match res {
IteratorError::Resync => ffi::GST_ITERATOR_RESYNC,
IteratorError::Error => ffi::GST_ITERATOR_ERROR,
},
}
}
unsafe extern "C" fn rs_iterator_resync<T, I: IteratorImpl<T>>(it: *mut ffi::GstIterator)
where
for<'a> T: FromValue<'a> + StaticType + ToValue + Send + 'static,
{
let it = it as *mut RsIterator<T, I>;
(*it).imp.resync();
}
#[derive(Clone)]
struct VecIteratorImpl<T> {
pos: usize,
items: Vec<T>,
}
impl<T> VecIteratorImpl<T>
where
for<'a> T: StaticType + ToValue + FromValue<'a> + Clone + Send + 'static,
{
fn new(items: Vec<T>) -> Self {
skip_assert_initialized!();
Self { pos: 0, items }
}
}
impl<T> IteratorImpl<T> for VecIteratorImpl<T>
where
for<'a> T: StaticType + ToValue + FromValue<'a> + Clone + Send + 'static,
{
fn next(&mut self) -> Option<Result<T, IteratorError>> {
if self.pos < self.items.len() {
let res = Ok(self.items[self.pos].clone());
self.pos += 1;
return Some(res);
}
None
}
fn resync(&mut self) {
self.pos = 0;
}
}
unsafe impl<T> Send for Iterator<T> {}
unsafe impl<T> Sync for Iterator<T> {}
unsafe extern "C" fn filter_trampoline<
T: for<'a> FromValue<'a> + StaticType + 'static,
F: Fn(T) -> bool + Send + Sync + 'static,
>(
value: gconstpointer,
func: gconstpointer,
) -> i32 {
let value = value as *const glib::gobject_ffi::GValue;
let func = func as *const glib::gobject_ffi::GValue;
let func = glib::gobject_ffi::g_value_get_boxed(func);
let func = &*(func as *const &(dyn Any + Send + Sync + 'static));
let func = func.downcast_ref::<F>().unwrap();
let value = &*(value as *const glib::Value);
let value = value.get::<T>().expect("Iterator filter_trampoline");
if func(value) {
0
} else {
-1
}
}
unsafe extern "C" fn filter_boxed_ref(boxed: gpointer) -> gpointer {
let boxed = Arc::from_raw(boxed as *const Box<dyn Any + Send + Sync + 'static>);
let copy = Arc::clone(&boxed);
// Forget it and keep it alive, we will still need it later
let _ = Arc::into_raw(boxed);
Arc::into_raw(copy) as gpointer
}
unsafe extern "C" fn filter_boxed_unref(boxed: gpointer) {
let _ = Arc::from_raw(boxed as *const Box<dyn Any + Send + Sync + 'static>);
}
unsafe extern "C" fn filter_boxed_get_type() -> glib::Type {
static TYPE: std::sync::OnceLock<glib::Type> = std::sync::OnceLock::new();
*TYPE.get_or_init(|| {
let iter_type_name = {
let mut idx = 0;
loop {
let iter_type_name = glib::gformat!("GstRsIteratorFilterBoxed-{}", idx);
if glib::gobject_ffi::g_type_from_name(iter_type_name.as_ptr())
== glib::gobject_ffi::G_TYPE_INVALID
{
break iter_type_name;
}
idx += 1;
}
};
let t = glib::Type::from_glib(glib::gobject_ffi::g_boxed_type_register_static(
iter_type_name.as_ptr(),
Some(filter_boxed_ref),
Some(filter_boxed_unref),
));
assert!(t.is_valid());
t
})
}
unsafe extern "C" fn find_trampoline<T, F: FnMut(T) -> bool>(
value: gconstpointer,
func: gconstpointer,
) -> i32
where
for<'a> T: FromValue<'a> + 'static,
{
let value = value as *const glib::gobject_ffi::GValue;
let func = func as *mut F;
let value = &*(value as *const glib::Value);
let value = value.get::<T>().expect("Iterator find_trampoline");
if (*func)(value) {
0
} else {
-1
}
}
unsafe extern "C" fn foreach_trampoline<T, F: FnMut(T)>(
value: *const glib::gobject_ffi::GValue,
func: gpointer,
) where
for<'a> T: FromValue<'a> + 'static,
{
let func = func as *mut F;
let value = &*(value as *const glib::Value);
let value = value.get::<T>().expect("Iterator foreach_trampoline");
(*func)(value);
}
unsafe extern "C" fn fold_trampoline<T, U, F: FnMut(U, T) -> Result<U, U>>(
value: *const glib::gobject_ffi::GValue,
ret: *mut glib::gobject_ffi::GValue,
func: gpointer,
) -> glib::ffi::gboolean
where
for<'a> T: FromValue<'a> + 'static,
{
let func = func as *mut F;
let value = &*(value as *const glib::Value);
let value = value.get::<T>().expect("Iterator fold_trampoline");
let accum = &mut *(glib::gobject_ffi::g_value_get_pointer(ret) as *mut Option<U>);
match (*func)(accum.take().unwrap(), value) {
Ok(next_accum) => {
*accum = Some(next_accum);
glib::ffi::GTRUE
}
Err(next_accum) => {
*accum = Some(next_accum);
glib::ffi::GFALSE
}
}
}
impl<T: StaticType + 'static> Clone for Iterator<T> {
#[inline]
fn clone(&self) -> Self {
unsafe { from_glib_full(ffi::gst_iterator_copy(self.to_glib_none().0)) }
}
}
impl<T> fmt::Debug for Iterator<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Iterator")
.field("iter", &self.iter)
.finish()
}
}
impl<T> Drop for Iterator<T> {
#[inline]
fn drop(&mut self) {
unsafe {
ffi::gst_iterator_free(self.iter.as_ptr());
}
}
}
impl<T> iter::IntoIterator for Iterator<T>
where
for<'a> T: FromValue<'a> + 'static,
{
type Item = Result<T, IteratorError>;
type IntoIter = StdIterator<T>;
fn into_iter(self) -> Self::IntoIter {
Self::IntoIter::new(self)
}
}
impl<T> glib::types::StaticType for Iterator<T> {
#[inline]
fn static_type() -> glib::types::Type {
unsafe { glib::translate::from_glib(ffi::gst_iterator_get_type()) }
}
}
impl<T: StaticType + 'static> glib::value::ValueType for Iterator<T> {
type Type = Self;
}
impl<T: StaticType + 'static> glib::value::ValueTypeOptional for Iterator<T> {}
unsafe impl<'a, T: StaticType + 'static> glib::value::FromValue<'a> for Iterator<T> {
type Checker = glib::value::GenericValueTypeOrNoneChecker<Self>;
unsafe fn from_value(value: &'a glib::Value) -> Self {
skip_assert_initialized!();
from_glib_none(
glib::gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *mut ffi::GstIterator
)
}
}
impl<T: StaticType + 'static> glib::value::ToValue for Iterator<T> {
fn to_value(&self) -> glib::Value {
let mut value = glib::Value::for_value_type::<Self>();
unsafe {
glib::gobject_ffi::g_value_set_boxed(
value.to_glib_none_mut().0,
self.to_glib_none().0 as *mut _,
)
}
value
}
fn value_type(&self) -> glib::Type {
Self::static_type()
}
}
impl<T: StaticType + 'static> glib::value::ToValueOptional for Iterator<T> {
fn to_value_optional(s: Option<&Self>) -> glib::Value {
skip_assert_initialized!();
let mut value = glib::Value::for_value_type::<Self>();
unsafe {
glib::gobject_ffi::g_value_set_boxed(
value.to_glib_none_mut().0,
s.to_glib_none().0 as *mut _,
)
}
value
}
}
impl<T: StaticType + 'static> From<Iterator<T>> for glib::Value {
fn from(v: Iterator<T>) -> glib::Value {
skip_assert_initialized!();
let mut value = glib::Value::for_value_type::<Iterator<T>>();
unsafe {
glib::gobject_ffi::g_value_take_boxed(
value.to_glib_none_mut().0,
v.into_glib_ptr() as *mut _,
)
}
value
}
}
#[doc(hidden)]
impl<T> glib::translate::GlibPtrDefault for Iterator<T> {
type GlibType = *mut ffi::GstIterator;
}
#[doc(hidden)]
unsafe impl<T: StaticType + 'static> TransparentPtrType for Iterator<T> {}
#[doc(hidden)]
impl<'a, T: 'static> glib::translate::ToGlibPtr<'a, *const ffi::GstIterator> for Iterator<T> {
type Storage = PhantomData<&'a Iterator<T>>;
#[inline]
fn to_glib_none(&'a self) -> glib::translate::Stash<'a, *const ffi::GstIterator, Self> {
glib::translate::Stash(self.iter.as_ptr(), PhantomData)
}
fn to_glib_full(&self) -> *const ffi::GstIterator {
unimplemented!()
}
}
#[doc(hidden)]
impl<'a, T: 'static> glib::translate::ToGlibPtrMut<'a, *mut ffi::GstIterator> for Iterator<T> {
type Storage = PhantomData<&'a mut Iterator<T>>;
#[inline]
fn to_glib_none_mut(
&'a mut self,
) -> glib::translate::StashMut<'a, *mut ffi::GstIterator, Self> {
glib::translate::StashMut(self.iter.as_ptr(), PhantomData)
}
}
#[doc(hidden)]
impl<T: StaticType> glib::translate::FromGlibPtrNone<*const ffi::GstIterator> for Iterator<T> {
#[inline]
unsafe fn from_glib_none(ptr: *const ffi::GstIterator) -> Self {
debug_assert_ne!(
glib::gobject_ffi::g_type_is_a((*ptr).type_, T::static_type().into_glib()),
glib::ffi::GFALSE
);
from_glib_full(ffi::gst_iterator_copy(ptr))
}
}
#[doc(hidden)]
impl<T: StaticType> glib::translate::FromGlibPtrNone<*mut ffi::GstIterator> for Iterator<T> {
#[inline]
unsafe fn from_glib_none(ptr: *mut ffi::GstIterator) -> Self {
debug_assert_ne!(
glib::gobject_ffi::g_type_is_a((*ptr).type_, T::static_type().into_glib()),
glib::ffi::GFALSE
);
from_glib_full(ffi::gst_iterator_copy(ptr))
}
}
#[doc(hidden)]
impl<T: StaticType> glib::translate::FromGlibPtrBorrow<*mut ffi::GstIterator> for Iterator<T> {
#[inline]
unsafe fn from_glib_borrow(ptr: *mut ffi::GstIterator) -> Borrowed<Self> {
debug_assert!(!ptr.is_null());
debug_assert_ne!(
glib::gobject_ffi::g_type_is_a((*ptr).type_, T::static_type().into_glib()),
glib::ffi::GFALSE
);
Borrowed::new(Self {
iter: ptr::NonNull::new_unchecked(ptr),
phantom: PhantomData,
})
}
}
#[doc(hidden)]
impl<T: StaticType> glib::translate::FromGlibPtrFull<*mut ffi::GstIterator> for Iterator<T> {
#[inline]
unsafe fn from_glib_full(ptr: *mut ffi::GstIterator) -> Self {
debug_assert!(!ptr.is_null());
debug_assert_ne!(
glib::gobject_ffi::g_type_is_a((*ptr).type_, T::static_type().into_glib()),
glib::ffi::GFALSE
);
Self {
iter: ptr::NonNull::new_unchecked(ptr),
phantom: PhantomData,
}
}
}
pub struct StdIterator<T> {
inner: Iterator<T>,
error: Option<IteratorError>,
}
impl<T> StdIterator<T> {
fn new(inner: Iterator<T>) -> Self {
skip_assert_initialized!();
Self { inner, error: None }
}
}
impl<T: StaticType + 'static> Clone for StdIterator<T> {
#[inline]
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: FromValue<'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(),
None => {}
}
let res = self.inner.next();
self.error = res.as_ref().err().copied();
res.transpose()
}
}
impl<T> iter::FusedIterator for StdIterator<T> where for<'a> T: FromValue<'a> + 'static {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_vec() {
crate::init().unwrap();
let vec = vec![1i32, 2, 3];
let mut it = Iterator::from_vec(vec);
let val = it.next();
assert_eq!(val, Ok(Some(1)));
let val = it.next();
assert_eq!(val, Ok(Some(2)));
let val = it.next();
assert_eq!(val, Ok(Some(3)));
assert_eq!(it.next(), Ok(None));
let vec = vec![1i32, 2, 3];
let mut it = Iterator::from_vec(vec);
let mut vals = Vec::new();
while let Ok(Some(res)) = it.next() {
vals.push(res);
}
assert_eq!(vals, [1, 2, 3]);
}
#[test]
fn test_filter() {
crate::init().unwrap();
let vec = vec![1i32, 2, 3];
let mut it = Iterator::from_vec(vec).filter(|val| val % 2 == 1);
let mut vals = Vec::new();
while let Ok(Some(res)) = it.next() {
vals.push(res);
}
assert_eq!(vals, [1, 3]);
}
#[test]
fn test_find() {
crate::init().unwrap();
// Our find
let vec = vec![1i32, 2, 3];
let val = Iterator::from_vec(vec).find(|val| val == 2);
assert_eq!(val.unwrap(), 2);
}
#[test]
fn test_foreach() {
crate::init().unwrap();
let vec = vec![1i32, 2, 3];
let mut sum = 0;
let res = Iterator::from_vec(vec).foreach(|val| sum += val);
assert_eq!(res, Ok(()));
assert_eq!(sum, 6);
}
#[test]
fn test_fold() {
crate::init().unwrap();
// Our fold
let vec = vec![1i32, 2, 3];
let res = Iterator::from_vec(vec).fold(0, |mut sum, val| {
sum += val;
Ok(sum)
});
assert_eq!(res.unwrap(), 6);
}
#[test]
fn test_std() {
crate::init().unwrap();
let mut it = Iterator::from_vec(vec![1i32, 2, 3]).into_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_into_iter() {
crate::init().unwrap();
let mut v = vec![1i32, 2, 3].into_iter();
for x in Iterator::from_vec(vec![1i32, 2, 3]) {
assert_eq!(x.unwrap(), v.next().unwrap());
}
assert_eq!(v.next(), None);
}
#[test]
fn test_std_resync_collect() {
use std::collections::BTreeSet;
use crate::prelude::*;
crate::init().unwrap();
let bin = crate::Bin::new();
let id1 = crate::ElementFactory::make("identity").build().unwrap();
let id2 = crate::ElementFactory::make("identity").build().unwrap();
bin.add(&id1).unwrap();
let mut it = bin.iterate_elements().into_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 crate::prelude::*;
crate::init().unwrap();
let bin = crate::Bin::new();
let id1 = crate::ElementFactory::make("identity").build().unwrap();
let id2 = crate::ElementFactory::make("identity").build().unwrap();
bin.add(&id1).unwrap();
let mut it = bin.iterate_elements().into_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);
}
}