use std::collections::HashSet;
use crate::{aictable::Aictable, builder::FactoryBuilder, error::Error};
pub struct Factory<T: Aictable> {
initial_value: T,
looping: bool,
rewind: bool,
cursor: T,
set: HashSet<T>,
}
impl<T: Aictable> Factory<T> {
pub fn new(initial_value: T, looping: bool, rewind: bool) -> Self {
let cursor = initial_value.clone();
Self {
initial_value,
looping,
rewind,
cursor,
set: HashSet::new(),
}
}
pub fn builder() -> FactoryBuilder<T> {
FactoryBuilder::default()
}
pub fn next(&mut self) -> Result<T, Error<T>> {
let start = self.cursor.clone();
while self.set.contains(&self.cursor) {
if self.looping {
self.cursor = self.cursor.wrapping_next();
if self.cursor == start {
return Err(Error::OutOfSpace);
}
} else {
self.cursor = self.cursor.saturating_next();
if self.cursor.is_max_reached() {
return Err(Error::MaxReached);
}
}
}
self.set.insert(self.cursor.clone());
let next = self.cursor.clone();
if self.looping {
self.cursor = self.cursor.wrapping_next();
} else {
self.cursor = self.cursor.saturating_next();
}
Ok(next)
}
pub fn remove(&mut self, id: T) -> bool {
if self.set.remove(&id) {
if self.rewind {
self.cursor = id;
}
return true;
}
false
}
pub fn reset(&mut self) {
self.cursor = self.initial_value.clone();
self.set.clear();
}
pub fn take_up(&mut self, id: T) -> Result<(), Error<T>> {
if self.set.contains(&id) {
return Err(Error::AlreadyExist(id));
}
self.set.insert(id);
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_factory() {
let mut factory = Factory::<u32>::builder().build();
assert_eq!(factory.next().unwrap(), 0);
assert_eq!(factory.next().unwrap(), 1);
factory.remove(1);
assert_eq!(factory.next().unwrap(), 2);
assert!(factory.take_up(2).is_err());
assert!(factory.take_up(3).is_ok());
assert!(factory.take_up(3).is_err());
factory.remove(3);
assert!(factory.take_up(3).is_ok());
assert_eq!(factory.next().unwrap(), 4);
factory.reset();
assert_eq!(factory.next().unwrap(), 0);
factory = Factory::<u32>::builder().initial_value(1).build();
assert_eq!(factory.next().unwrap(), 1);
factory.reset();
assert_eq!(factory.next().unwrap(), 1);
factory = Factory::<u32>::builder().initial_value(u32::MAX).build();
assert_eq!(factory.next().unwrap(), u32::MAX);
assert!(factory.next().is_err());
factory = Factory::<u32>::builder()
.initial_value(u32::MAX)
.looping(true)
.build();
assert_eq!(factory.next().unwrap(), u32::MAX);
assert_eq!(factory.next().unwrap(), u32::MIN);
factory = Factory::<u32>::builder().rewind(true).build();
assert_eq!(factory.next().unwrap(), 0);
assert_eq!(factory.next().unwrap(), 1);
factory.remove(1);
assert_eq!(factory.next().unwrap(), 1);
factory.remove(0);
assert_eq!(factory.next().unwrap(), 0);
assert_eq!(factory.next().unwrap(), 2);
assert_eq!(factory.next().unwrap(), 3);
factory.remove(0);
factory.remove(1);
assert_eq!(factory.next().unwrap(), 1);
}
}