trait-obj-list 0.1.2

List of unsized trait objects, stored in a flat array
Documentation
#[path = "../src/test_utils.rs"]
mod utils;

use core::any::Any;

use trait_obj_list::DynList;

utils::for_each_list_type! {
	#[test]
	fn create_and_drop_empty<T>() {
		let l = DynList::<dyn Any, T>::new();
		std::mem::drop(l);
	}

	#[test]
	fn push_and_get<T>() {
		let mut l = DynList::<dyn Any, T>::new();
		assert!(l.is_empty());
		l.push(123i32);
		l.push(456u64);
		l.push(7i32);
		assert!(!l.is_empty());
		assert_eq!(l.len(), 3);

		let mut it = l.iter();
		assert_eq!(it.len(), 3);
		let i1 = it.next().unwrap();
		assert_eq!(it.len(), 2);
		let i2 = it.next().unwrap();
		assert_eq!(it.len(), 1);
		let i3 = it.next().unwrap();
		assert_eq!(it.len(), 0);
		assert!(it.next().is_none());

		assert_eq!(i1.downcast_ref::<i32>().copied(), Some(123));
		assert_eq!(i1.downcast_ref::<u64>().copied(), None);
		assert_eq!(i2.downcast_ref::<u64>().copied(), Some(456));
		assert_eq!(i2.downcast_ref::<i32>().copied(), None);
		assert_eq!(i3.downcast_ref::<i32>().copied(), Some(7));
		assert_eq!(i3.downcast_ref::<u64>().copied(), None);

		core::mem::drop(l);
	}

	#[test]
	fn iter_mut<T>() {
		let mut l = DynList::<dyn Any, T>::new();
		l.push(123i32);
		l.push(456u64);
		l.push(7i32);

		for i in l.iter_mut() {
			// need to dereference here: https://doc.rust-lang.org/std/any/index.html#smart-pointers-and-dyn-any
			if let Some(i) = (*i).downcast_mut::<i32>() {
				*i = *i + 1;
			} else if let Some(i) = (*i).downcast_mut::<u64>() {
				*i = *i + 1;
			} else {
				panic!("{:?}", (*i).type_id());
			}
		}

		let mut it = l.iter();
		assert_eq!(it.len(), 3);
		let i1 = it.next().unwrap();
		assert_eq!(it.len(), 2);
		let i2 = it.next().unwrap();
		assert_eq!(it.len(), 1);
		let i3 = it.next().unwrap();
		assert_eq!(it.len(), 0);
		assert!(it.next().is_none());

		assert_eq!(i1.downcast_ref::<i32>().copied(), Some(124));
		assert_eq!(i1.downcast_ref::<u64>().copied(), None);
		assert_eq!(i2.downcast_ref::<u64>().copied(), Some(457));
		assert_eq!(i2.downcast_ref::<i32>().copied(), None);
		assert_eq!(i3.downcast_ref::<i32>().copied(), Some(8));
		assert_eq!(i3.downcast_ref::<u64>().copied(), None);

		core::mem::drop(l);
	}

	#[test]
	fn zero_sized_types<T>() {
		let mut l = DynList::<dyn Any, T>::new();
		l.push(());
		l.push(456u64);
		l.push(());

		let mut it = l.iter();
		assert_eq!(it.len(), 3);
		let i1 = it.next().unwrap();
		assert_eq!(it.len(), 2);
		let i2 = it.next().unwrap();
		assert_eq!(it.len(), 1);
		let i3 = it.next().unwrap();
		assert_eq!(it.len(), 0);
		assert!(it.next().is_none());

		assert_eq!(i1.downcast_ref::<()>().copied(), Some(()));
		assert_eq!(i1.downcast_ref::<u64>().copied(), None);
		assert_eq!(i2.downcast_ref::<u64>().copied(), Some(456));
		assert_eq!(i2.downcast_ref::<i32>().copied(), None);
		assert_eq!(i3.downcast_ref::<()>().copied(), Some(()));
		assert_eq!(i3.downcast_ref::<u64>().copied(), None);
	}

	#[test]
	fn into_ptr_iter<T>() {
		let mut l = DynList::<dyn Any, T>::new();
		l.push(123i32);
		l.push(456u64);
		l.push(7i32);

		let mut it = l.into_ptrs_iter();
		{
			assert_eq!(it.len(), 3);
			let i1 = it.next().unwrap();
			assert_eq!(it.len(), 2);
			let i2 = it.next().unwrap();
			assert_eq!(it.len(), 1);
			let i3 = it.next().unwrap();
			assert_eq!(it.len(), 0);
			assert!(it.next().is_none());

			assert_eq!(unsafe { &*i1 }.downcast_ref::<i32>().copied(), Some(123));
			assert_eq!(unsafe { &*i1 }.downcast_ref::<u64>().copied(), None);
			assert_eq!(unsafe { &*i2 }.downcast_ref::<u64>().copied(), Some(456));
			assert_eq!(unsafe { &*i2 }.downcast_ref::<i32>().copied(), None);
			assert_eq!(unsafe { &*i3 }.downcast_ref::<i32>().copied(), Some(7));
			assert_eq!(unsafe { &*i3 }.downcast_ref::<u64>().copied(), None);
		}
		std::mem::drop(it);
	}

	#[test]
	fn into_box_iter<T>() {
		let mut l = DynList::<dyn Any, T>::new();
		l.push(123i32);
		l.push(456u64);
		l.push(7i32);

		let bi = l.into_box_iter();
		assert_eq!(bi.len(), 3);

		let v = bi.collect::<Vec<_>>();
		assert_eq!(v.len(), 3);
		utils::assert_any_eq(&*v[0], 123i32);
		utils::assert_any_eq(&*v[1], 456u64);
		utils::assert_any_eq(&*v[2], 7i32);
	}

	#[test]
	fn eq<T>() {
		#[cfg_attr(feature = "ptr_meta", ptr_meta::pointee)]
		trait AnyEq: Any { fn any_eq(&self, other: &dyn AnyEq) -> bool; }
		trait_obj_list::impl_from_impl!(dyn AnyEq);

		impl PartialEq for dyn AnyEq {
			fn eq(&self, other: &Self) -> bool {
				self.any_eq(other)
			}
		}
		impl AnyEq for i32 { fn any_eq(&self,other: &dyn AnyEq) -> bool {
			(other as &dyn Any).downcast_ref::<Self>() == Some(self)
		} }
		impl AnyEq for i64 { fn any_eq(&self,other: &dyn AnyEq) -> bool {
			(other as &dyn Any).downcast_ref::<Self>() == Some(self)
		} }

		let mut l1 = DynList::<dyn AnyEq, T>::new();
		l1.push(123i32);
		l1.push(456i64);
		l1.push(789i32);

		let mut l2 = DynList::<dyn AnyEq, T>::new();
		l2.push(123i32);
		l2.push(456i64);
		l2.push(789i32);

		let mut l3 = DynList::<dyn AnyEq, T>::new();
		l3.push(123i64);
		l3.push(456i32);
		l3.push(789i64);

		assert!(l1 == l1);
		assert!(l1 == l2);
		assert!(l1 != l3);
	}
}

#[test]
fn rev_iter() {
	let mut l = DynList::<dyn Any, trait_obj_list::types::DoubleLinked>::new();
	l.push(123i32);
	l.push(456u64);
	l.push(7i32);

	let mut it = l.iter().rev();
	assert_eq!(it.len(), 3);
	let i1 = it.next().unwrap();
	assert_eq!(it.len(), 2);
	let i2 = it.next().unwrap();
	assert_eq!(it.len(), 1);
	let i3 = it.next().unwrap();
	assert_eq!(it.len(), 0);
	assert!(it.next().is_none());

	assert_eq!(i1.downcast_ref::<i32>().copied(), Some(7));
	assert_eq!(i1.downcast_ref::<u64>().copied(), None);
	assert_eq!(i2.downcast_ref::<u64>().copied(), Some(456));
	assert_eq!(i2.downcast_ref::<i32>().copied(), None);
	assert_eq!(i3.downcast_ref::<i32>().copied(), Some(123));
	assert_eq!(i3.downcast_ref::<u64>().copied(), None);

	core::mem::drop(l);
}

#[test]
fn mixed_iter_double_linked() {
	let mut l = DynList::<dyn Any, trait_obj_list::types::DoubleLinked>::new();
	l.push(123i32);
	l.push(456u64);
	l.push(7i32);
	l.push([1u32, 2, 3]);

	let mut it = l.iter();
	assert_eq!(it.len(), 4);
	let i1 = it.next().unwrap();
	assert_eq!(it.len(), 3);
	let i4 = it.next_back().unwrap();
	assert_eq!(it.len(), 2);
	let i2 = it.next().unwrap();
	assert_eq!(it.len(), 1);
	let i3 = it.next().unwrap();
	assert_eq!(it.len(), 0);
	assert!(it.next().is_none());
	assert!(it.next_back().is_none());

	assert_eq!(i1.downcast_ref::<i32>().copied(), Some(123));
	assert_eq!(i1.downcast_ref::<u64>().copied(), None);
	assert_eq!(i2.downcast_ref::<u64>().copied(), Some(456));
	assert_eq!(i2.downcast_ref::<i32>().copied(), None);
	assert_eq!(i3.downcast_ref::<i32>().copied(), Some(7));
	assert_eq!(i3.downcast_ref::<u64>().copied(), None);
	assert_eq!(i4.downcast_ref::<[u32; 3]>().copied(), Some([1, 2, 3]));
	assert_eq!(i4.downcast_ref::<u64>().copied(), None);
}

#[test]
fn mixed_iter_mut_double_linked() {
	let mut l = DynList::<dyn Any, trait_obj_list::types::DoubleLinked>::new();
	l.push(123i32);
	l.push(456u64);
	l.push(7i32);

	let mut it = l.iter_mut();
	assert_eq!(it.len(), 3);
	let i1 = it.next().unwrap();
	assert_eq!(it.len(), 2);
	let i3 = it.next_back().unwrap();
	assert_eq!(it.len(), 1);
	let i2 = it.next().unwrap();
	assert_eq!(it.len(), 0);
	assert!(it.next().is_none());
	assert!(it.next_back().is_none());

	assert_eq!(i1.downcast_ref::<i32>().copied(), Some(123));
	assert_eq!(i1.downcast_ref::<u64>().copied(), None);
	assert_eq!(i2.downcast_ref::<u64>().copied(), Some(456));
	assert_eq!(i2.downcast_ref::<i32>().copied(), None);
	assert_eq!(i3.downcast_ref::<i32>().copied(), Some(7));
	assert_eq!(i3.downcast_ref::<u64>().copied(), None);
}