use std::collections::HashSet;
pub struct Unique64 {
available_ids: HashSet<u64>,
next_id: u64,
}
impl Unique64 {
pub fn new() -> Self {
Self {
available_ids: HashSet::new(),
next_id: 0,
}
}
pub fn get_next(&mut self) -> u64 {
let mut selection_option: Option<u64> = None;
if let Some(id) = self.available_ids.iter().next() {
selection_option = Some(*id);
}
if let Some(selection) = selection_option {
self.available_ids.remove(&selection);
return selection;
}
let selection = self.next_id;
self.next_id += 1;
selection
}
pub fn remove(&mut self, value: u64) {
if self.available_ids.contains(&value) || value >= self.next_id {
panic!("Unique64: Attempted to remove a non-existent ID.")
}
self.available_ids.insert(value);
}
}
impl Default for Unique64 {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn working_correctly() {
let mut dispatcher = Unique64::new();
for _ in 0..1_000 {
dispatcher.get_next();
}
assert!(dispatcher.next_id == 1_000);
for i in 500..1000 {
dispatcher.remove(i);
}
assert!(dispatcher.next_id == 1_000);
assert!(dispatcher.available_ids.len() == 500);
for _ in 500..1_000 {
let g = dispatcher.get_next();
assert!((500..1_000).contains(&g))
}
assert!(dispatcher.next_id == 1_000);
assert!(dispatcher.available_ids.is_empty());
let cool = dispatcher.get_next();
assert!(cool == 1_000);
assert!(dispatcher.available_ids.is_empty());
assert!(dispatcher.next_id == 1_001);
for i in 0..1_000 {
dispatcher.remove(i);
}
assert!(dispatcher.available_ids.len() == 1_000);
assert!(dispatcher.next_id == 1_001);
}
#[test]
fn very_specific() {
let mut dispatcher = Unique64::new();
for _ in 0..5 {
dispatcher.get_next();
}
dispatcher.remove(1);
assert!(dispatcher.available_ids.get(&1).is_some());
assert!(dispatcher.get_next() == 1);
assert!(dispatcher.next_id == 5);
dispatcher.remove(4);
assert!(dispatcher.available_ids.get(&4).is_some());
assert!(dispatcher.get_next() == 4);
assert!(dispatcher.next_id == 5);
dispatcher.remove(2);
dispatcher.remove(3);
assert!(dispatcher.available_ids.get(&3).is_some());
assert!(dispatcher.available_ids.get(&2).is_some());
let testing = dispatcher.get_next();
assert!(testing == 2 || testing == 3);
let testing = dispatcher.get_next();
assert!(testing == 2 || testing == 3);
assert!(dispatcher.next_id == 5);
}
#[test]
#[should_panic]
pub fn wrong() {
let mut dispatcher = Unique64::new();
dispatcher.remove(5)
}
#[test]
#[should_panic]
pub fn wrong_again() {
let mut dispatcher = Unique64::new();
dispatcher.remove(0)
}
#[test]
#[should_panic]
pub fn common_mistake() {
let mut dispatcher = Unique64::new();
for _ in 0..1_000 {
dispatcher.get_next();
}
dispatcher.remove(7);
dispatcher.remove(7);
}
#[test]
pub fn readme_example() {
let mut dispatcher = Unique64::new();
let x = dispatcher.get_next();
assert!(x == 0);
let y = dispatcher.get_next();
assert!(y == 1);
dispatcher.remove(x);
let z = dispatcher.get_next();
assert!(z == 0);
}
}