#![doc(html_root_url = "https://docs.rs/num-iter/0.1")]
#![no_std]
use core::ops::{Add, Bound, RangeBounds, Sub};
use core::usize;
use num_integer::Integer;
use num_traits::{CheckedAdd, One, ToPrimitive, Zero};
#[derive(Clone)]
pub struct Range<A> {
state: A,
stop: A,
one: A,
}
#[inline]
pub fn range<A>(start: A, stop: A) -> Range<A>
where
A: Add<A, Output = A> + PartialOrd + Clone + One,
{
Range {
state: start,
stop,
one: One::one(),
}
}
#[inline]
fn unsigned<T: ToPrimitive>(x: &T) -> Option<u128> {
match x.to_u128() {
Some(u) => Some(u),
None => Some(x.to_i128()? as u128),
}
}
impl<A> RangeBounds<A> for Range<A> {
fn start_bound(&self) -> Bound<&A> {
Bound::Included(&self.state)
}
fn end_bound(&self) -> Bound<&A> {
Bound::Excluded(&self.stop)
}
}
impl<A> Iterator for Range<A>
where
A: Add<A, Output = A> + PartialOrd + Clone + ToPrimitive,
{
type Item = A;
#[inline]
fn next(&mut self) -> Option<A> {
if self.state < self.stop {
let result = self.state.clone();
self.state = self.state.clone() + self.one.clone();
Some(result)
} else {
None
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
if self.state >= self.stop {
return (0, Some(0));
}
if let Some(a) = unsigned(&self.state) {
if let Some(b) = unsigned(&self.stop) {
return match b.wrapping_sub(a).to_usize() {
Some(len) => (len, Some(len)),
None => (usize::MAX, None),
};
}
}
(0, None)
}
}
impl<A> DoubleEndedIterator for Range<A>
where
A: Integer + Clone + ToPrimitive,
{
#[inline]
fn next_back(&mut self) -> Option<A> {
if self.stop > self.state {
self.stop = self.stop.clone() - self.one.clone();
Some(self.stop.clone())
} else {
None
}
}
}
#[derive(Clone)]
pub struct RangeInclusive<A> {
range: Range<A>,
done: bool,
}
#[inline]
pub fn range_inclusive<A>(start: A, stop: A) -> RangeInclusive<A>
where
A: Add<A, Output = A> + PartialOrd + Clone + One,
{
RangeInclusive {
range: range(start, stop),
done: false,
}
}
impl<A> RangeBounds<A> for RangeInclusive<A> {
fn start_bound(&self) -> Bound<&A> {
Bound::Included(&self.range.state)
}
fn end_bound(&self) -> Bound<&A> {
Bound::Included(&self.range.stop)
}
}
impl<A> Iterator for RangeInclusive<A>
where
A: Add<A, Output = A> + PartialOrd + Clone + ToPrimitive,
{
type Item = A;
#[inline]
fn next(&mut self) -> Option<A> {
match self.range.next() {
Some(x) => Some(x),
None => {
if !self.done && self.range.state == self.range.stop {
self.done = true;
Some(self.range.stop.clone())
} else {
None
}
}
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let (lo, hi) = self.range.size_hint();
if self.done {
(lo, hi)
} else {
let lo = lo.saturating_add(1);
let hi = match hi {
Some(x) => x.checked_add(1),
None => None,
};
(lo, hi)
}
}
}
impl<A> DoubleEndedIterator for RangeInclusive<A>
where
A: Sub<A, Output = A> + Integer + Clone + ToPrimitive,
{
#[inline]
fn next_back(&mut self) -> Option<A> {
if self.range.stop > self.range.state {
let result = self.range.stop.clone();
self.range.stop = self.range.stop.clone() - self.range.one.clone();
Some(result)
} else if !self.done && self.range.state == self.range.stop {
self.done = true;
Some(self.range.stop.clone())
} else {
None
}
}
}
#[derive(Clone)]
pub struct RangeStep<A> {
state: A,
stop: A,
step: A,
rev: bool,
}
#[inline]
pub fn range_step<A>(start: A, stop: A, step: A) -> RangeStep<A>
where
A: CheckedAdd + PartialOrd + Clone + Zero,
{
let rev = step < Zero::zero();
RangeStep {
state: start,
stop,
step,
rev,
}
}
impl<A> Iterator for RangeStep<A>
where
A: CheckedAdd + PartialOrd + Clone,
{
type Item = A;
#[inline]
fn next(&mut self) -> Option<A> {
if (self.rev && self.state > self.stop) || (!self.rev && self.state < self.stop) {
let result = self.state.clone();
match self.state.checked_add(&self.step) {
Some(x) => self.state = x,
None => self.state = self.stop.clone(),
}
Some(result)
} else {
None
}
}
}
#[derive(Clone)]
pub struct RangeStepInclusive<A> {
state: A,
stop: A,
step: A,
rev: bool,
done: bool,
}
#[inline]
pub fn range_step_inclusive<A>(start: A, stop: A, step: A) -> RangeStepInclusive<A>
where
A: CheckedAdd + PartialOrd + Clone + Zero,
{
let rev = step < Zero::zero();
RangeStepInclusive {
state: start,
stop,
step,
rev,
done: false,
}
}
impl<A> Iterator for RangeStepInclusive<A>
where
A: CheckedAdd + PartialOrd + Clone + PartialEq,
{
type Item = A;
#[inline]
fn next(&mut self) -> Option<A> {
if !self.done
&& ((self.rev && self.state >= self.stop) || (!self.rev && self.state <= self.stop))
{
let result = self.state.clone();
match self.state.checked_add(&self.step) {
Some(x) => self.state = x,
None => self.done = true,
}
Some(result)
} else {
None
}
}
}
#[derive(Clone)]
pub struct RangeFrom<A> {
state: A,
one: A,
}
#[inline]
pub fn range_from<A>(start: A) -> RangeFrom<A>
where
A: Add<A, Output = A> + Clone + One,
{
RangeFrom {
state: start,
one: One::one(),
}
}
impl<A> RangeBounds<A> for RangeFrom<A> {
fn start_bound(&self) -> Bound<&A> {
Bound::Included(&self.state)
}
fn end_bound(&self) -> Bound<&A> {
Bound::Unbounded
}
}
impl<A> Iterator for RangeFrom<A>
where
A: Add<A, Output = A> + Clone,
{
type Item = A;
#[inline]
fn next(&mut self) -> Option<A> {
let result = self.state.clone();
self.state = self.state.clone() + self.one.clone();
Some(result)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(usize::MAX, None)
}
}
#[derive(Clone)]
pub struct RangeStepFrom<A> {
state: A,
step: A,
}
#[inline]
pub fn range_step_from<A>(start: A, step: A) -> RangeStepFrom<A>
where
A: Add<A, Output = A> + Clone,
{
RangeStepFrom { state: start, step }
}
impl<A> Iterator for RangeStepFrom<A>
where
A: Add<A, Output = A> + Clone,
{
type Item = A;
#[inline]
fn next(&mut self) -> Option<A> {
let result = self.state.clone();
self.state = self.state.clone() + self.step.clone();
Some(result)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(usize::MAX, None)
}
}
#[cfg(test)]
mod tests {
use core::cmp::Ordering;
use core::iter;
use core::ops::{Add, Mul};
use core::{isize, usize};
use num_traits::{One, ToPrimitive};
#[test]
fn test_range() {
struct Foo;
impl ToPrimitive for Foo {
fn to_i64(&self) -> Option<i64> {
None
}
fn to_u64(&self) -> Option<u64> {
None
}
}
impl Add<Foo> for Foo {
type Output = Foo;
fn add(self, _: Foo) -> Foo {
Foo
}
}
impl PartialEq for Foo {
fn eq(&self, _: &Foo) -> bool {
true
}
}
impl PartialOrd for Foo {
fn partial_cmp(&self, _: &Foo) -> Option<Ordering> {
None
}
}
impl Clone for Foo {
fn clone(&self) -> Foo {
Foo
}
}
impl Mul<Foo> for Foo {
type Output = Foo;
fn mul(self, _: Foo) -> Foo {
Foo
}
}
impl One for Foo {
fn one() -> Foo {
Foo
}
}
assert!(super::range(0, 5).eq([0, 1, 2, 3, 4].iter().cloned()));
assert!(super::range(-10, -1).eq([-10, -9, -8, -7, -6, -5, -4, -3, -2].iter().cloned()));
assert!(super::range(0, 5).rev().eq([4, 3, 2, 1, 0].iter().cloned()));
assert_eq!(super::range(200, -5).count(), 0);
assert_eq!(super::range(200, -5).rev().count(), 0);
assert_eq!(super::range(200, 200).count(), 0);
assert_eq!(super::range(200, 200).rev().count(), 0);
assert_eq!(super::range(0, 100).size_hint(), (100, Some(100)));
assert_eq!(
super::range(usize::MAX - 1, usize::MAX).size_hint(),
(1, Some(1))
);
assert_eq!(super::range(-10, -1).size_hint(), (9, Some(9)));
assert_eq!(
super::range(isize::MIN, isize::MAX).size_hint(),
(usize::MAX, Some(usize::MAX))
);
}
#[test]
fn test_range_128() {
use core::{i128, u128};
assert!(super::range(0i128, 5).eq([0, 1, 2, 3, 4].iter().cloned()));
assert!(super::range(-10i128, -1).eq([-10, -9, -8, -7, -6, -5, -4, -3, -2].iter().cloned()));
assert!(super::range(0u128, 5)
.rev()
.eq([4, 3, 2, 1, 0].iter().cloned()));
assert_eq!(
super::range(i128::MIN, i128::MIN + 1).size_hint(),
(1, Some(1))
);
assert_eq!(
super::range(i128::MAX - 1, i128::MAX).size_hint(),
(1, Some(1))
);
assert_eq!(
super::range(i128::MIN, i128::MAX).size_hint(),
(usize::MAX, None)
);
assert_eq!(
super::range(u128::MAX - 1, u128::MAX).size_hint(),
(1, Some(1))
);
assert_eq!(
super::range(0, usize::MAX as u128).size_hint(),
(usize::MAX, Some(usize::MAX))
);
assert_eq!(
super::range(0, usize::MAX as u128 + 1).size_hint(),
(usize::MAX, None)
);
assert_eq!(super::range(0, i128::MAX).size_hint(), (usize::MAX, None));
}
#[test]
fn test_range_inclusive() {
assert!(super::range_inclusive(0, 5).eq([0, 1, 2, 3, 4, 5].iter().cloned()));
assert!(super::range_inclusive(0, 5)
.rev()
.eq([5, 4, 3, 2, 1, 0].iter().cloned()));
assert_eq!(super::range_inclusive(200, -5).count(), 0);
assert_eq!(super::range_inclusive(200, -5).rev().count(), 0);
assert!(super::range_inclusive(200, 200).eq(iter::once(200)));
assert!(super::range_inclusive(200, 200).rev().eq(iter::once(200)));
assert_eq!(
super::range_inclusive(isize::MIN, isize::MAX - 1).size_hint(),
(usize::MAX, Some(usize::MAX))
);
assert_eq!(
super::range_inclusive(isize::MIN, isize::MAX).size_hint(),
(usize::MAX, None)
);
}
#[test]
fn test_range_inclusive_128() {
use core::i128;
assert!(super::range_inclusive(0u128, 5).eq([0, 1, 2, 3, 4, 5].iter().cloned()));
assert!(super::range_inclusive(0u128, 5)
.rev()
.eq([5, 4, 3, 2, 1, 0].iter().cloned()));
assert_eq!(super::range_inclusive(200i128, -5).count(), 0);
assert_eq!(super::range_inclusive(200i128, -5).rev().count(), 0);
assert!(super::range_inclusive(200u128, 200).eq(iter::once(200)));
assert!(super::range_inclusive(200u128, 200)
.rev()
.eq(iter::once(200)));
assert_eq!(
super::range_inclusive(isize::MIN as i128, isize::MAX as i128 - 1).size_hint(),
(usize::MAX, Some(usize::MAX))
);
assert_eq!(
super::range_inclusive(isize::MIN as i128, isize::MAX as i128).size_hint(),
(usize::MAX, None)
);
assert_eq!(
super::range_inclusive(isize::MIN as i128, isize::MAX as i128 + 1).size_hint(),
(usize::MAX, None)
);
assert_eq!(
super::range_inclusive(i128::MIN, i128::MAX).size_hint(),
(usize::MAX, None)
);
}
#[test]
fn test_range_step() {
assert!(super::range_step(0, 20, 5).eq([0, 5, 10, 15].iter().cloned()));
assert!(super::range_step(20, 0, -5).eq([20, 15, 10, 5].iter().cloned()));
assert!(super::range_step(20, 0, -6).eq([20, 14, 8, 2].iter().cloned()));
assert!(super::range_step(200u8, 255, 50).eq([200u8, 250].iter().cloned()));
assert!(super::range_step(200, -5, 1).eq(iter::empty()));
assert!(super::range_step(200, 200, 1).eq(iter::empty()));
}
#[test]
fn test_range_step_128() {
use core::u128::MAX as UMAX;
assert!(super::range_step(0u128, 20, 5).eq([0, 5, 10, 15].iter().cloned()));
assert!(super::range_step(20i128, 0, -5).eq([20, 15, 10, 5].iter().cloned()));
assert!(super::range_step(20i128, 0, -6).eq([20, 14, 8, 2].iter().cloned()));
assert!(super::range_step(UMAX - 55, UMAX, 50).eq([UMAX - 55, UMAX - 5].iter().cloned()));
assert!(super::range_step(200i128, -5, 1).eq(iter::empty()));
assert!(super::range_step(200i128, 200, 1).eq(iter::empty()));
}
#[test]
fn test_range_step_inclusive() {
assert!(super::range_step_inclusive(0, 20, 5).eq([0, 5, 10, 15, 20].iter().cloned()));
assert!(super::range_step_inclusive(20, 0, -5).eq([20, 15, 10, 5, 0].iter().cloned()));
assert!(super::range_step_inclusive(20, 0, -6).eq([20, 14, 8, 2].iter().cloned()));
assert!(super::range_step_inclusive(200u8, 255, 50).eq([200u8, 250].iter().cloned()));
assert!(super::range_step_inclusive(200, -5, 1).eq(iter::empty()));
assert!(super::range_step_inclusive(200, 200, 1).eq(iter::once(200)));
}
#[test]
fn test_range_step_inclusive_128() {
use core::u128::MAX as UMAX;
assert!(super::range_step_inclusive(0u128, 20, 5).eq([0, 5, 10, 15, 20].iter().cloned()));
assert!(super::range_step_inclusive(20i128, 0, -5).eq([20, 15, 10, 5, 0].iter().cloned()));
assert!(super::range_step_inclusive(20i128, 0, -6).eq([20, 14, 8, 2].iter().cloned()));
assert!(super::range_step_inclusive(UMAX - 55, UMAX, 50)
.eq([UMAX - 55, UMAX - 5].iter().cloned()));
assert!(super::range_step_inclusive(200i128, -5, 1).eq(iter::empty()));
assert!(super::range_step_inclusive(200i128, 200, 1).eq(iter::once(200)));
}
#[test]
fn test_range_from() {
assert!(super::range_from(10u8)
.take(5)
.eq([10, 11, 12, 13, 14].iter().cloned()));
assert_eq!(super::range_from(10u8).size_hint(), (usize::MAX, None));
}
#[test]
fn test_range_step_from() {
assert!(super::range_step_from(10u8, 2u8)
.take(5)
.eq([10, 12, 14, 16, 18].iter().cloned()));
assert_eq!(
super::range_step_from(10u8, 2u8).size_hint(),
(usize::MAX, None)
);
assert!(super::range_step_from(10u8, 1u8)
.take(5)
.eq([10, 11, 12, 13, 14].iter().cloned()));
assert_eq!(
super::range_step_from(10u8, 1u8).size_hint(),
(usize::MAX, None)
);
assert!(super::range_step_from(10u8, 0u8)
.take(5)
.eq([10, 10, 10, 10, 10].iter().cloned()));
assert_eq!(
super::range_step_from(10u8, 0u8).size_hint(),
(usize::MAX, None)
);
assert!(super::range_step_from(10i8, 2i8)
.take(5)
.eq([10, 12, 14, 16, 18].iter().cloned()));
assert_eq!(
super::range_step_from(10i8, 2i8).size_hint(),
(usize::MAX, None)
);
assert!(super::range_step_from(10i8, 1i8)
.take(5)
.eq([10, 11, 12, 13, 14].iter().cloned()));
assert_eq!(
super::range_step_from(10i8, 1i8).size_hint(),
(usize::MAX, None)
);
assert!(super::range_step_from(10i8, 0i8)
.take(5)
.eq([10, 10, 10, 10, 10].iter().cloned()));
assert_eq!(
super::range_step_from(10i8, 0i8).size_hint(),
(usize::MAX, None)
);
assert!(super::range_step_from(10i8, -1i8)
.take(5)
.eq([10, 9, 8, 7, 6].iter().cloned()));
assert_eq!(
super::range_step_from(10i8, -1i8).size_hint(),
(usize::MAX, None)
);
assert!(super::range_step_from(10i8, -2i8)
.take(5)
.eq([10, 8, 6, 4, 2].iter().cloned()));
assert_eq!(
super::range_step_from(10i8, -2i8).size_hint(),
(usize::MAX, None)
);
}
}