use duration::FloatDuration;
use std::iter;
#[derive(Debug, Clone)]
pub struct Subdivide {
start: FloatDuration,
step_size: FloatDuration,
len: usize,
index: usize,
}
impl Subdivide {
fn new(start: FloatDuration, end: FloatDuration, steps: usize) -> Subdivide {
assert!(steps >= 2, "subdivide requires at least two steps");
let step_size = (end - start) / (steps - 1) as f64;
Subdivide {
start: start,
step_size: step_size,
len: steps,
index: 0,
}
}
pub fn step_size(&self) -> FloatDuration {
self.step_size
}
}
impl Iterator for Subdivide {
type Item = FloatDuration;
#[inline]
fn next(&mut self) -> Option<FloatDuration> {
if self.index >= self.len {
None
} else {
let index = self.index;
self.index += 1;
Some(self.start + self.step_size * (index as f64))
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let left = self.len - self.index;
(left, Some(left))
}
}
impl DoubleEndedIterator for Subdivide {
fn next_back(&mut self) -> Option<FloatDuration> {
if self.index >= self.len {
None
} else {
self.len -= 1;
let index = self.len;
Some(self.start + self.step_size * (index as f64))
}
}
}
impl ExactSizeIterator for Subdivide {}
pub fn subdivide(begin: FloatDuration, end: FloatDuration, steps: usize) -> Subdivide {
Subdivide::new(begin, end, steps)
}
pub fn subdivide_with_step(begin: FloatDuration,
end: FloatDuration,
steps: usize)
-> iter::Zip<Subdivide, iter::Repeat<FloatDuration>> {
let sub = subdivide(begin, end, steps);
let step_size = sub.step_size();
sub.zip(iter::repeat(step_size))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_subdivide() {
let s = subdivide(FloatDuration::zero(), FloatDuration::minutes(1.0), 3);
let s_rev = s.clone().rev();
assert_eq!(s.collect::<Vec<_>>(),
vec![FloatDuration::zero(),
FloatDuration::seconds(30.0),
FloatDuration::minutes(1.0)]);
assert_eq!(s_rev.collect::<Vec<_>>(),
vec![FloatDuration::minutes(1.0),
FloatDuration::seconds(30.0),
FloatDuration::zero()]);
assert_eq!(subdivide(FloatDuration::zero(), FloatDuration::zero(), 3).collect::<Vec<_>>(),
vec![FloatDuration::zero(),
FloatDuration::zero(),
FloatDuration::zero()]);
}
#[should_panic]
#[test]
fn test_subdivide_panic() {
subdivide(FloatDuration::zero(), FloatDuration::minutes(1.0), 1);
}
}