1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
use super::CliffSearch;
use core::borrow::Borrow;

/// An iterator that determines the maximum supported load by walking an iterator until the system
/// cannot keep up.
///
/// See the [crate-level documentation](..) for details.
#[derive(Debug, Clone)]
pub struct LoadIterator<I> {
    max_in: core::ops::Range<usize>,
    last: Option<usize>,
    overloaded: bool,
    iter: I,
}

impl<I, T> CliffSearch for LoadIterator<I>
where
    I: Iterator<Item = T>,
    T: Borrow<usize>,
{
    fn overloaded(&mut self) {
        self.overloaded = true;
    }

    fn estimate(&self) -> core::ops::Range<usize> {
        self.max_in.clone()
    }
}

impl<I, T> Iterator for LoadIterator<I>
where
    I: Iterator<Item = T>,
    T: Borrow<usize>,
{
    type Item = usize;
    fn next(&mut self) -> Option<Self::Item> {
        if let Some(ref mut last) = self.last {
            if self.overloaded {
                self.max_in.end = *last;
            } else {
                self.max_in.start = *last;
            }
        }

        if self.overloaded {
            return None;
        }

        let next = *self.iter.next()?.borrow();
        self.last = Some(next);
        Some(next)
    }
}

impl<I, T> From<I> for LoadIterator<I::IntoIter>
where
    I: IntoIterator<Item = T>,
    T: Borrow<usize>,
{
    fn from(v: I) -> Self {
        LoadIterator {
            max_in: 0..usize::max_value(),
            last: None,
            overloaded: false,
            iter: v.into_iter(),
        }
    }
}

#[test]
fn linear_nofail() {
    let mut scale = LoadIterator::from(&[1, 2, 3, 4]);
    assert_eq!(scale.next(), Some(1));
    assert_eq!(scale.next(), Some(2));
    assert_eq!(scale.next(), Some(3));
    assert_eq!(scale.next(), Some(4));
    assert_eq!(scale.next(), None);
    assert_eq!(scale.estimate(), 4..usize::max_value());

    // check that it continues to be terminated
    assert_eq!(scale.next(), None);
    // even after another "failed"
    scale.overloaded();
    assert_eq!(scale.next(), None);
}

#[test]
fn linear_fail() {
    let mut scale = LoadIterator::from(&[1, 2, 3, 4]);
    assert_eq!(scale.next(), Some(1));
    assert_eq!(scale.next(), Some(2));
    scale.overloaded();
    assert_eq!(scale.next(), None);
    assert_eq!(scale.estimate(), 1..2);

    // check that it continues to be terminated
    assert_eq!(scale.next(), None);
    // even after another "failed"
    scale.overloaded();
    assert_eq!(scale.next(), None);
}