use crate::seq_num::SeqNum;
use std::iter::Iterator;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Default, Debug)]
pub struct Sequence<T>
where
T: SeqNum,
{
next: T,
incr: T,
#[cfg_attr(feature = "serde", serde(default = "SeqNum::max_val"))]
max: T,
}
impl<T> Sequence<T>
where
T: SeqNum,
{
#[must_use]
pub fn new() -> Self {
Self {
next: T::zero(),
incr: T::one(),
max: T::max_val(),
}
}
#[must_use]
fn dead() -> Self {
Self {
next: T::zero(),
incr: T::zero(),
max: T::max_val(),
}
}
#[must_use]
pub fn start_with(val: T) -> Self {
Self {
next: val,
incr: T::one(),
max: T::max_val(),
}
}
#[must_use]
pub fn start_after(val: T) -> Self {
match val.checked_add(T::one()) {
Some(next) => Self {
next,
incr: T::one(),
max: T::max_val(),
},
None => Self::dead(),
}
}
pub fn start_after_highest(values: &mut dyn Iterator<Item = &T>) -> Self {
Self::start_after(
*values
.reduce(|x, y| std::cmp::max(x, y))
.unwrap_or(&T::zero()),
)
}
pub fn with_start_end_increment(start: T, end: T, incr: T) -> Self {
Self {
next: start,
incr,
max: end,
}
}
#[must_use]
pub fn with_increment(mut self, incr: T) -> Self {
if self.is_active() {
self.incr = incr;
}
self
}
pub fn continue_after(&mut self, val: T) {
match val.checked_add(self.incr) {
Some(candidate) => {
self.next = std::cmp::max(self.next, candidate);
}
None => {
self.set_passive();
}
}
}
pub fn peek(&self) -> Option<T> {
if self.is_passive() {
None
} else {
Some(self.next)
}
}
fn set_passive(&mut self) {
self.incr = T::zero();
}
fn is_active(&self) -> bool {
self.incr != T::zero()
}
fn is_passive(&self) -> bool {
self.incr == T::zero()
}
}
impl<T> Iterator for Sequence<T>
where
T: SeqNum,
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if self.is_passive() {
None
} else {
let current = self.next;
match self.next.checked_add(self.incr) {
Some(next) => {
if next > self.max {
self.set_passive();
} else {
self.next = next;
}
}
None => {
self.set_passive();
}
}
Some(current)
}
}
}
#[cfg(test)]
mod test {
use super::Sequence;
#[test]
fn test_sequence() {
let mut sequence = Sequence::<usize>::new();
assert_eq!(sequence.next(), Some(0_usize));
assert_eq!(sequence.next(), Some(1_usize));
sequence.continue_after(5);
assert_eq!(sequence.next(), Some(6));
sequence.continue_after(15);
sequence.continue_after(7);
sequence.continue_after(0);
assert_eq!(sequence.next(), Some(16));
assert_eq!(sequence.peek(), Some(17));
assert_eq!(sequence.peek(), Some(17));
assert_eq!(sequence.next(), Some(17));
}
#[test]
fn test_increment() {
let mut sequence = Sequence::<u8>::new().with_increment(5);
assert_eq!(sequence.next(), Some(0));
assert_eq!(sequence.next(), Some(5));
assert_eq!(sequence.next(), Some(10));
sequence.continue_after(152);
assert_eq!(sequence.next(), Some(157));
assert_eq!(sequence.next(), Some(162));
sequence.continue_after(251);
assert_eq!(sequence.next(), None);
}
#[test]
fn test_exhaust() {
let mut sequence = Sequence::<u64>::new();
sequence.continue_after(u64::MAX - 2);
assert!(sequence.is_active());
assert!(sequence.next().is_some());
assert!(sequence.peek().is_some());
assert!(sequence.peek().is_some());
assert!(sequence.next().is_some());
assert!(sequence.peek().is_none());
assert!(sequence.next().is_none());
}
#[cfg(feature = "serde")]
#[test]
fn test_serde() {
let mut sequence = Sequence::<u32>::with_start_end_increment(22, 99, 11);
assert_eq!(sequence.next(), Some(22));
let s = serde_json::to_string(&sequence).unwrap();
assert_eq!(&*s, r#"{"next":33,"incr":11,"max":99}"#);
let mut sequence2: Sequence<u32> = serde_json::from_str(&*s).unwrap();
assert_eq!(sequence2.next(), Some(33));
assert_eq!(sequence2.next(), Some(44));
assert_eq!(sequence2.next(), Some(55));
assert_eq!(sequence2.next(), Some(66));
assert_eq!(sequence2.next(), Some(77));
assert_eq!(sequence2.next(), Some(88));
assert_eq!(sequence2.next(), Some(99));
assert_eq!(sequence2.next(), None);
let old_format = r#"{"next":88,"incr":11}"#;
let mut sequence3: Sequence<u32> = serde_json::from_str(&old_format).unwrap();
assert_eq!(sequence3.next(), Some(88));
assert_eq!(sequence3.next(), Some(99));
assert_eq!(sequence3.next(), Some(110));
assert_eq!(sequence3.next(), Some(121));
}
#[test]
fn test_iter() {
assert_eq!(
Sequence::<u8>::with_start_end_increment(23, 38, 3).sum::<u8>(),
183
);
}
}