You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

99 lines
2.3 KiB

//! Iterator types
pub mod either;
/// A bespoke iterator type with an exact size over elements.
///
/// This has an advantage over using simple inline slices (e.g `[1,2,3]`) as they currently cannot implement `IntoIterator` properly, and will always yield references.
/// This can be a hinderance when you want an ad-hoc iterator of non-`Copy` items.
/// The iterator types created from this macro consume the values.
///
/// # Example
/// ```
/// # use ad_hoc_iter::iter;
/// let sum: i32 = iter![1, 2].chain(3..=4).chain(iter![5, 6]).sum();
/// assert_eq!(sum, 21);
/// ```
#[macro_export] macro_rules! iter {
(@) => (0usize);
(@ $x:tt $($xs:tt)* ) => (1usize + $crate::iter!(@ $($xs)*));
($($value:expr),*) => {
{
use ::std::mem::MaybeUninit;
use ::std::ops::Drop;
struct Arr<T>([MaybeUninit<T>; $crate::iter!(@ $($value)*)], usize);
impl<T> Arr<T>
{
const LEN: usize = $crate::iter!(@ $($value)*);
}
impl<T> Iterator for Arr<T>
{
type Item = T;
fn next(&mut self) -> Option<Self::Item>
{
if self.1 >= self.0.len() {
None
} else {
//take one
let one = unsafe {
::std::mem::replace(&mut self.0[self.1], MaybeUninit::uninit()).assume_init()
};
self.1+=1;
Some(one)
}
}
#[inline] fn size_hint(&self) -> (usize, Option<usize>)
{
(Self::LEN, Some(Self::LEN))
}
}
impl<T> ::std::iter::FusedIterator for Arr<T>{}
impl<T> ::std::iter::ExactSizeIterator for Arr<T>{}
impl<T> Drop for Arr<T>
{
fn drop(&mut self) {
if ::std::mem::needs_drop::<T>() {
for idx in self.1..self.0.len() {
unsafe {
::std::mem::replace(&mut self.0[idx], MaybeUninit::uninit()).assume_init();
}
}
}
}
}
Arr([$(MaybeUninit::new($value)),*], 0)
}
}
}
#[cfg(test)]
mod tests
{
#[test]
fn iter_over()
{
const EXPECT: usize = 10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1;
let iter = iter![10,9,8,7,6,5,4,3,2,1];
assert_eq!(iter.len(), 10);
assert_eq!(iter.sum::<usize>(), EXPECT);
}
#[test]
fn non_copy()
{
macro_rules! string {
($val:literal) => (String::from($val));
}
const EXPECT: &str = "Hello world!";
let whole: String = iter![string!("Hell"), string!("o "), string!("world"), string!("!")].collect();
assert_eq!(EXPECT, &whole[..]);
}
}