use core::{
    num::NonZeroUsize,
    ops::{Bound, RangeBounds},
};
use index_type::{
    IndexType,
    typed_enumerate::TypedIteratorExt,
    typed_range::{TypedRange, TypedRangeFrom, TypedRangeInclusive, TypedRangeIterExt},
};

#[derive(IndexType, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct MyIndex(u32);

#[derive(IndexType, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
struct SmallIndex(u8);

mod typed_range {
    use super::*;

    #[test]
    fn test_normal_range() {
        let iter = (MyIndex(0)..MyIndex(5)).iter();
        let collected: Vec<_> = iter.collect();
        assert_eq!(
            collected,
            vec![MyIndex(0), MyIndex(1), MyIndex(2), MyIndex(3), MyIndex(4)]
        );
    }

    #[test]
    fn test_empty_range_equal() {
        let iter = (MyIndex(5)..MyIndex(5)).iter();
        let collected: Vec<_> = iter.collect();
        assert!(collected.is_empty());
    }

    #[test]
    fn test_empty_range_start_greater() {
        let iter = (MyIndex(5)..MyIndex(3)).iter();
        let collected: Vec<_> = iter.collect();
        assert!(collected.is_empty());
    }

    #[test]
    fn test_single_element_range() {
        let iter = (MyIndex(3)..MyIndex(4)).iter();
        let collected: Vec<_> = iter.collect();
        assert_eq!(collected, vec![MyIndex(3)]);
    }

    #[test]
    fn test_len() {
        assert_eq!((MyIndex(0)..MyIndex(5)).iter().len(), 5);
        assert_eq!((MyIndex(5)..MyIndex(5)).iter().len(), 0);
        assert_eq!((MyIndex(5)..MyIndex(3)).iter().len(), 0);
        assert_eq!((MyIndex(0)..MyIndex(1)).iter().len(), 1);
    }

    #[test]
    fn test_count() {
        assert_eq!((MyIndex(0)..MyIndex(5)).iter().count(), 5);
        assert_eq!((MyIndex(5)..MyIndex(5)).iter().count(), 0);
    }

    #[test]
    #[allow(clippy::iter_nth_zero)]
    fn test_nth() {
        let mut iter = (MyIndex(0)..MyIndex(10)).iter();
        assert_eq!(iter.nth(0), Some(MyIndex(0)));
        assert_eq!(iter.nth(2), Some(MyIndex(3)));
        assert_eq!(iter.nth(100), None);
        assert_eq!(iter.next(), None);
    }

    #[test]
    fn test_last() {
        assert_eq!((MyIndex(0)..MyIndex(5)).iter().last(), Some(MyIndex(4)));
        assert_eq!((MyIndex(5)..MyIndex(5)).iter().last(), None);
    }

    #[test]
    fn test_size_hint() {
        let iter = (MyIndex(0)..MyIndex(5)).iter();
        assert_eq!(iter.size_hint(), (5, Some(5)));
    }

    #[test]
    fn test_double_ended() {
        let iter = (MyIndex(0)..MyIndex(5)).iter();
        let collected: Vec<_> = iter.rev().collect();
        assert_eq!(
            collected,
            vec![MyIndex(4), MyIndex(3), MyIndex(2), MyIndex(1), MyIndex(0)]
        );
    }

    #[test]
    fn test_double_ended_empty() {
        let iter = (MyIndex(5)..MyIndex(5)).iter();
        let collected: Vec<_> = iter.rev().collect();
        assert!(collected.is_empty());
    }

    #[test]
    fn test_nth_back() {
        let mut iter = (MyIndex(0)..MyIndex(10)).iter();
        assert_eq!(iter.nth_back(0), Some(MyIndex(9)));
        assert_eq!(iter.nth_back(2), Some(MyIndex(6)));
        assert_eq!(iter.nth_back(100), None);
        assert_eq!(iter.next_back(), None);
    }

    #[test]
    fn test_exact_size_iterator() {
        let iter = (MyIndex(0)..MyIndex(5)).iter();
        assert_eq!(iter.len(), 5);
    }

    #[test]
    fn test_fused_iterator() {
        let mut iter = (MyIndex(0)..MyIndex(3)).iter();
        assert_eq!(iter.next(), Some(MyIndex(0)));
        assert_eq!(iter.next(), Some(MyIndex(1)));
        assert_eq!(iter.next(), Some(MyIndex(2)));
        assert_eq!(iter.next(), None);
        assert_eq!(iter.next(), None);
    }

    #[test]
    fn test_is_sorted() {
        assert!((MyIndex(0)..MyIndex(5)).iter().is_sorted());
    }

    #[test]
    fn test_min_max() {
        assert_eq!((MyIndex(0)..MyIndex(5)).iter().min(), Some(MyIndex(0)));
        assert_eq!((MyIndex(0)..MyIndex(5)).iter().max(), Some(MyIndex(4)));
        assert_eq!((MyIndex(5)..MyIndex(5)).iter().min(), None);
        assert_eq!((MyIndex(5)..MyIndex(5)).iter().max(), None);
    }

    #[test]
    fn test_typed_enumerate() {
        let indexed: Vec<_> = (MyIndex(10)..MyIndex(13))
            .iter()
            .typed_enumerate::<MyIndex>()
            .collect();
        assert_eq!(
            indexed,
            vec![
                (MyIndex(0), MyIndex(10)),
                (MyIndex(1), MyIndex(11)),
                (MyIndex(2), MyIndex(12))
            ]
        );
    }

    #[test]
    fn test_typed_enumerate_supports_reverse_and_mixed_iteration() {
        let reversed: Vec<_> = (MyIndex(10)..MyIndex(13))
            .iter()
            .typed_enumerate::<MyIndex>()
            .rev()
            .map(|(idx, value)| (idx.to_raw_index(), value.to_raw_index()))
            .collect();
        assert_eq!(reversed, vec![(2, 12), (1, 11), (0, 10)]);

        let mut iter = (MyIndex(10)..MyIndex(13))
            .iter()
            .typed_enumerate::<MyIndex>();
        assert_eq!(iter.next(), Some((MyIndex(0), MyIndex(10))));
        assert_eq!(iter.next_back(), Some((MyIndex(2), MyIndex(12))));
        assert_eq!(iter.next(), Some((MyIndex(1), MyIndex(11))));
        assert_eq!(iter.next_back(), None);
    }

    #[test]
    fn test_typed_enumerate_panics_on_overflow() {
        let result = std::panic::catch_unwind(|| {
            let _ = (0usize..256).typed_enumerate::<SmallIndex>().count();
        });
        assert!(result.is_err());
    }
}

mod typed_range_from_iter {
    use super::*;

    #[test]
    fn test_range_from() {
        let iter = (MyIndex(0)..).iter();
        let collected: Vec<_> = iter.take(5).collect();
        assert_eq!(
            collected,
            vec![MyIndex(0), MyIndex(1), MyIndex(2), MyIndex(3), MyIndex(4)]
        );
    }

    #[test]
    #[allow(clippy::iter_nth_zero)]
    fn test_nth() {
        let mut iter = (MyIndex(10)..).iter();
        assert_eq!(iter.nth(0), Some(MyIndex(10)));
        assert_eq!(iter.nth(5), Some(MyIndex(16)));
    }

    #[test]
    fn test_range_from_panics_on_overflow_like_std() {
        let mut iter = (SmallIndex(254)..).iter();
        assert_eq!(iter.next(), Some(SmallIndex(254)));
        let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
            let _ = iter.next();
        }));
        assert!(result.is_err());
    }

    #[test]
    fn test_range_from_nth_panics_on_overflow_like_std() {
        let mut iter = (SmallIndex(250)..).iter();
        let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
            let _ = iter.nth(10);
        }));
        assert!(result.is_err());
    }

    #[test]
    fn test_min() {
        let iter = (MyIndex(5)..).iter();
        assert_eq!(iter.min(), Some(MyIndex(5)));
    }

    #[test]
    fn test_is_sorted() {
        assert!((MyIndex(0)..).iter().is_sorted());
    }

    #[test]
    fn test_fused_iterator() {
        let mut iter = (MyIndex(0)..).iter();
        assert_eq!(iter.next(), Some(MyIndex(0)));
        assert_eq!(iter.next(), Some(MyIndex(1)));
    }
}

mod raw_conversions {
    use super::*;

    #[test]
    fn test_typed_range_from_raw_and_into_raw_preserve_bounds() {
        let range = TypedRange::from_raw(MyIndex(2)..MyIndex(5));
        assert_eq!(range.start, MyIndex(2));
        assert_eq!(range.end, MyIndex(5));

        let raw = range.into_raw();
        assert_eq!(raw.start, MyIndex(2));
        assert_eq!(raw.end, MyIndex(5));
    }

    #[test]
    fn test_typed_range_from_raw_preserves_empty_bounds() {
        let range = TypedRange::from_raw(MyIndex(5)..MyIndex(3));
        assert_eq!(range.start, MyIndex(5));
        assert_eq!(range.end, MyIndex(3));
        assert!(range.is_empty());

        let raw = range.into_raw();
        assert_eq!(raw.start, MyIndex(5));
        assert_eq!(raw.end, MyIndex(3));
    }

    #[test]
    fn test_typed_range_fields_update_during_iteration() {
        let mut range = TypedRange::from_raw(MyIndex(2)..MyIndex(5));

        assert_eq!(range.next(), Some(MyIndex(2)));
        assert_eq!(range.start, MyIndex(3));
        assert_eq!(range.end, MyIndex(5));

        assert_eq!(range.next_back(), Some(MyIndex(4)));
        assert_eq!(range.start, MyIndex(3));
        assert_eq!(range.end, MyIndex(4));
    }

    #[test]
    fn test_typed_range_from_from_raw_and_into_raw_preserve_start() {
        let range = TypedRangeFrom::from_raw(MyIndex(7)..);
        assert_eq!(range.start, MyIndex(7));

        let raw = range.into_raw();
        assert_eq!(raw.start, MyIndex(7));
    }

    #[test]
    fn test_typed_range_from_field_updates_during_iteration() {
        let mut range = TypedRangeFrom::from_raw(MyIndex(7)..);

        assert_eq!(range.next(), Some(MyIndex(7)));
        assert_eq!(range.start, MyIndex(8));

        assert_eq!(range.nth(2), Some(MyIndex(10)));
        assert_eq!(range.start, MyIndex(11));
    }

    #[test]
    fn test_typed_range_inclusive_from_raw_and_into_raw_preserve_non_empty_bounds() {
        let range = TypedRangeInclusive::from_raw(MyIndex(2)..=MyIndex(5));
        assert_eq!(range.start(), MyIndex(2));
        assert_eq!(range.end(), MyIndex(5));
        assert!(!range.is_empty());

        let raw = range.into_raw();
        assert_eq!(raw.start(), &MyIndex(2));
        assert_eq!(raw.end(), &MyIndex(5));
        assert_eq!(raw.end_bound(), Bound::Included(&MyIndex(5)));
        assert!(!raw.is_empty());
    }

    #[test]
    fn test_typed_range_inclusive_from_raw_preserves_empty_non_exhausted_bounds() {
        let range = TypedRangeInclusive::from_raw(MyIndex(5)..=MyIndex(3));
        assert_eq!(range.start(), MyIndex(5));
        assert_eq!(range.end(), MyIndex(3));
        assert!(range.is_empty());

        let raw = range.into_raw();
        assert_eq!(raw.start(), &MyIndex(5));
        assert_eq!(raw.end(), &MyIndex(3));
        assert_eq!(raw.end_bound(), Bound::Included(&MyIndex(3)));
        assert!(raw.is_empty());
    }

    #[test]
    fn test_typed_range_inclusive_from_raw_preserves_exhausted_std_range_state() {
        let mut raw = 2usize..=4usize;
        assert_eq!(raw.by_ref().collect::<Vec<_>>(), vec![2, 3, 4]);
        assert_eq!(raw.start(), &4);
        assert_eq!(raw.end(), &4);
        assert_eq!(raw.end_bound(), Bound::Excluded(&4));
        assert!(raw.is_empty());

        let mut range = TypedRangeInclusive::from_raw(raw);
        assert_eq!(range.start(), 4);
        assert_eq!(range.end(), 4);
        assert!(range.is_empty());
        assert_eq!(range.len(), 0);
        assert_eq!(range.next(), None);
    }

    #[test]
    fn test_typed_range_inclusive_from_raw_lossy_drops_exhausted_std_range_state() {
        let mut raw = 2usize..=4usize;
        let _ = raw.by_ref().count();
        assert_eq!(raw.start(), &4);
        assert_eq!(raw.end(), &4);
        assert_eq!(raw.end_bound(), Bound::Excluded(&4));
        assert!(raw.is_empty());

        let mut range = TypedRangeInclusive::from_raw_lossy(raw);
        assert_eq!(range.start(), 4);
        assert_eq!(range.end(), 4);
        assert!(!range.is_empty());
        assert_eq!(range.len(), 1);
        assert_eq!(range.next(), Some(4));
        assert!(range.is_empty());
        assert_eq!(range.next(), None);
    }

    #[test]
    fn test_typed_range_inclusive_into_raw_is_lossy_for_exhausted_ranges() {
        let mut raw = 3usize..=3usize;
        assert_eq!(raw.next(), Some(3));
        assert_eq!(raw.start(), &3);
        assert_eq!(raw.end(), &3);
        assert_eq!(raw.end_bound(), Bound::Excluded(&3));
        assert!(raw.is_empty());

        let range = TypedRangeInclusive::from_raw(raw);
        assert!(range.is_empty());
        assert_eq!(range.start(), 3);
        assert_eq!(range.end(), 3);

        let raw_roundtrip = range.into_raw();
        assert_eq!(raw_roundtrip.start(), &3);
        assert_eq!(raw_roundtrip.end(), &3);
        assert_eq!(raw_roundtrip.end_bound(), Bound::Included(&3));
        assert!(!raw_roundtrip.is_empty());
        assert_eq!(raw_roundtrip.collect::<Vec<_>>(), vec![3]);
    }

    #[test]
    fn test_typed_range_inclusive_accessors_update_during_iteration() {
        let mut range = TypedRangeInclusive::from_raw(MyIndex(2)..=MyIndex(5));

        assert_eq!(range.next(), Some(MyIndex(2)));
        assert_eq!(range.start(), MyIndex(3));
        assert_eq!(range.end(), MyIndex(5));
        assert!(!range.is_empty());

        assert_eq!(range.next_back(), Some(MyIndex(5)));
        assert_eq!(range.start(), MyIndex(3));
        assert_eq!(range.end(), MyIndex(4));
        assert!(!range.is_empty());
    }
}

mod typed_range_inclusive_iter {
    use super::*;

    #[test]
    fn test_normal_range() {
        let iter = (MyIndex(0)..=MyIndex(4)).iter();
        let collected: Vec<_> = iter.collect();
        assert_eq!(
            collected,
            vec![MyIndex(0), MyIndex(1), MyIndex(2), MyIndex(3), MyIndex(4)]
        );
    }

    #[test]
    fn test_empty_range_start_greater() {
        let iter = (MyIndex(5)..=MyIndex(3)).iter();
        let collected: Vec<_> = iter.collect();
        assert!(collected.is_empty());
    }

    #[test]
    fn test_empty_range_equal() {
        let iter = (MyIndex(5)..=MyIndex(4)).iter();
        let collected: Vec<_> = iter.collect();
        assert!(collected.is_empty());
    }

    #[test]
    fn test_single_element_range() {
        let iter = (MyIndex(3)..=MyIndex(3)).iter();
        let collected: Vec<_> = iter.collect();
        assert_eq!(collected, vec![MyIndex(3)]);
    }

    #[test]
    fn test_len() {
        assert_eq!((MyIndex(0)..=MyIndex(4)).iter().len(), 5);
        assert_eq!((MyIndex(5)..=MyIndex(3)).iter().len(), 0);
        assert_eq!((MyIndex(3)..=MyIndex(3)).iter().len(), 1);
        assert_eq!((MyIndex(5)..=MyIndex(4)).iter().len(), 0);
    }

    #[test]
    fn test_count() {
        assert_eq!((MyIndex(0)..=MyIndex(4)).iter().count(), 5);
        assert_eq!((MyIndex(5)..=MyIndex(3)).iter().count(), 0);
        assert_eq!((MyIndex(3)..=MyIndex(3)).iter().count(), 1);
    }

    #[test]
    #[allow(clippy::iter_nth_zero)]
    fn test_nth() {
        let mut iter = (MyIndex(0)..=MyIndex(9)).iter();
        assert_eq!(iter.nth(0), Some(MyIndex(0)));
        assert_eq!(iter.nth(2), Some(MyIndex(3)));
        assert_eq!(iter.nth(9), None);
    }

    #[test]
    fn test_nth_independent() {
        let mut iter = (MyIndex(0)..=MyIndex(9)).iter();
        assert_eq!(iter.nth(2), Some(MyIndex(2)));
    }

    #[test]
    fn test_nth_exhaust() {
        let mut iter = (MyIndex(0)..=MyIndex(9)).iter();
        assert_eq!(iter.nth(10), None);
        assert_eq!(iter.nth(100), None);
        assert_eq!(iter.next(), None);
    }

    #[test]
    fn test_last() {
        assert_eq!((MyIndex(0)..=MyIndex(4)).iter().last(), Some(MyIndex(4)));
        assert_eq!((MyIndex(3)..=MyIndex(3)).iter().last(), Some(MyIndex(3)));
        assert_eq!((MyIndex(5)..=MyIndex(3)).iter().last(), None);
    }

    #[test]
    fn test_size_hint() {
        let iter = (MyIndex(0)..=MyIndex(4)).iter();
        assert_eq!(iter.size_hint(), (5, Some(5)));
    }

    #[test]
    fn test_double_ended() {
        let iter = (MyIndex(0)..=MyIndex(4)).iter();
        let collected: Vec<_> = iter.rev().collect();
        assert_eq!(
            collected,
            vec![MyIndex(4), MyIndex(3), MyIndex(2), MyIndex(1), MyIndex(0)]
        );
    }

    #[test]
    fn test_double_ended_single_element() {
        let iter = (MyIndex(3)..=MyIndex(3)).iter();
        let collected: Vec<_> = iter.rev().collect();
        assert_eq!(collected, vec![MyIndex(3)]);
    }

    #[test]
    fn test_double_ended_empty() {
        let iter = (MyIndex(5)..=MyIndex(3)).iter();
        let collected: Vec<_> = iter.rev().collect();
        assert!(collected.is_empty());
    }

    #[test]
    fn test_nth_back() {
        let mut iter = (MyIndex(0)..=MyIndex(9)).iter();
        assert_eq!(iter.nth_back(0), Some(MyIndex(9)));
        assert_eq!(iter.nth_back(2), Some(MyIndex(6)));
        assert_eq!(iter.nth_back(9), None);
        assert_eq!(iter.next_back(), None);
    }

    #[test]
    fn test_exact_size_iterator() {
        let iter = (MyIndex(0)..=MyIndex(4)).iter();
        assert_eq!(iter.len(), 5);
    }

    #[test]
    fn test_fused_iterator() {
        let mut iter = (MyIndex(0)..=MyIndex(2)).iter();
        assert_eq!(iter.next(), Some(MyIndex(0)));
        assert_eq!(iter.next(), Some(MyIndex(1)));
        assert_eq!(iter.next(), Some(MyIndex(2)));
        assert_eq!(iter.next(), None);
        assert_eq!(iter.next(), None);
    }

    #[test]
    fn test_min_max() {
        assert_eq!((MyIndex(0)..=MyIndex(4)).iter().min(), Some(MyIndex(0)));
        assert_eq!((MyIndex(0)..=MyIndex(4)).iter().max(), Some(MyIndex(4)));
        assert_eq!((MyIndex(5)..=MyIndex(3)).iter().min(), None);
        assert_eq!((MyIndex(5)..=MyIndex(3)).iter().max(), None);
    }

    #[test]
    fn test_is_sorted() {
        assert!((MyIndex(0)..=MyIndex(4)).iter().is_sorted());
    }
}

mod boundary_tests {
    use super::*;

    #[test]
    fn test_small_index_wrapping() {
        let iter = (SmallIndex(253)..SmallIndex(255)).iter();
        let collected: Vec<_> = iter.collect();
        assert_eq!(collected, vec![SmallIndex(253), SmallIndex(254)]);
    }

    #[test]
    fn test_small_index_at_limit() {
        let iter = (SmallIndex(0)..SmallIndex(254)).iter();
        let count = iter.count();
        assert_eq!(count, 254);
    }

    #[test]
    fn test_small_index_inclusive_at_limit() {
        let iter = (SmallIndex(0)..=SmallIndex(253)).iter();
        let count = iter.count();
        assert_eq!(count, 254);
    }

    #[test]
    fn test_nonzero_index_range() {
        #[derive(IndexType, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
        struct NonZeroIdx(NonZeroUsize);

        let iter = (NonZeroIdx(NonZeroUsize::new(1).unwrap())
            ..NonZeroIdx(NonZeroUsize::new(5).unwrap()))
            .iter();
        let collected: Vec<_> = iter.collect();
        assert_eq!(collected.len(), 4);
    }
}

mod double_ended_equivalence {
    use super::*;

    #[test]
    fn test_range_rev_equals_reversed() {
        let forward: Vec<_> = (MyIndex(0)..MyIndex(5)).iter().collect();
        let reversed: Vec<_> = (MyIndex(0)..MyIndex(5)).iter().rev().collect();
        let expected_rev: Vec<_> = forward.iter().copied().rev().collect();
        assert_eq!(reversed, expected_rev);
    }

    #[test]
    fn test_inclusive_rev_equals_reversed() {
        let forward: Vec<_> = (MyIndex(0)..=MyIndex(4)).iter().collect();
        let reversed: Vec<_> = (MyIndex(0)..=MyIndex(4)).iter().rev().collect();
        let expected_rev: Vec<_> = forward.iter().copied().rev().collect();
        assert_eq!(reversed, expected_rev);
    }

    #[test]
    fn test_mixed_iteration() {
        let mut iter = (MyIndex(0)..MyIndex(10)).iter();
        assert_eq!(iter.next(), Some(MyIndex(0)));
        assert_eq!(iter.next_back(), Some(MyIndex(9)));
        assert_eq!(iter.next(), Some(MyIndex(1)));
        assert_eq!(iter.next_back(), Some(MyIndex(8)));
    }

    #[test]
    fn test_mixed_iteration_inclusive() {
        let mut iter = (MyIndex(0)..=MyIndex(9)).iter();
        assert_eq!(iter.next(), Some(MyIndex(0)));
        assert_eq!(iter.next_back(), Some(MyIndex(9)));
        assert_eq!(iter.next(), Some(MyIndex(1)));
        assert_eq!(iter.next_back(), Some(MyIndex(8)));
    }
}

mod edge_case_iteration {
    use super::*;

    #[test]
    fn test_take() {
        let iter = (MyIndex(0)..).iter().take(3);
        let collected: Vec<_> = iter.collect();
        assert_eq!(collected, vec![MyIndex(0), MyIndex(1), MyIndex(2)]);
    }

    #[test]
    fn test_skip() {
        let iter = (MyIndex(0)..MyIndex(5)).iter().skip(2);
        let collected: Vec<_> = iter.collect();
        assert_eq!(collected, vec![MyIndex(2), MyIndex(3), MyIndex(4)]);
    }

    #[test]
    fn test_skip_inclusive() {
        let iter = (MyIndex(0)..=MyIndex(4)).iter().skip(2);
        let collected: Vec<_> = iter.collect();
        assert_eq!(collected, vec![MyIndex(2), MyIndex(3), MyIndex(4)]);
    }

    #[test]
    fn test_chain() {
        let a: Vec<_> = (MyIndex(0)..MyIndex(2)).iter().collect();
        let b: Vec<_> = (MyIndex(2)..MyIndex(4)).iter().collect();
        let combined: Vec<_> = a.into_iter().chain(b).collect();
        assert_eq!(
            combined,
            vec![MyIndex(0), MyIndex(1), MyIndex(2), MyIndex(3)]
        );
    }

    #[test]
    fn test_zip() {
        let indices: Vec<_> = (MyIndex(0)..MyIndex(3)).iter().collect();
        let values = [10, 20, 30];
        let zipped: Vec<_> = indices.iter().zip(values.iter()).collect();
        assert_eq!(zipped.len(), 3);
    }

    #[test]
    fn test_enumerate() {
        let indexed: Vec<_> = (MyIndex(0)..MyIndex(3)).iter().enumerate().collect();
        assert_eq!(
            indexed,
            vec![(0, MyIndex(0)), (1, MyIndex(1)), (2, MyIndex(2))]
        );
    }

    #[test]
    fn test_map() {
        let mapped: Vec<_> = (MyIndex(0)..MyIndex(3)).iter().map(|i| i.0 * 2).collect();
        assert_eq!(mapped, vec![0, 2, 4]);
    }

    #[test]
    fn test_filter() {
        let filtered: Vec<_> = (MyIndex(0)..MyIndex(5))
            .iter()
            .filter(|i| i.0 % 2 == 0)
            .collect();
        assert_eq!(filtered, vec![MyIndex(0), MyIndex(2), MyIndex(4)]);
    }

    #[test]
    fn test_fold() {
        let sum = (MyIndex(0)..MyIndex(5))
            .iter()
            .fold(0u32, |acc, i| acc + i.0);
        assert_eq!(sum, 10);
    }
}
