use std::{time::{SystemTime, UNIX_EPOCH}, collections::HashMap};
use super::bin_array::BinArray;
#[cfg(feature = "python")]
use pyo3::prelude::*;
#[cfg_attr(feature = "python", pyclass(get_all))]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Item {
pub include: BinArray,
pub exclude: BinArray,
pub reserved: BinArray,
pub references: HashMap<u32, u128>,
pub exhausted: bool,
pub increment: u32,
}
impl Item {
pub fn new() -> Self {
Self {
include: BinArray::new(),
exclude: BinArray::new(),
reserved: BinArray::new(),
references: HashMap::new(),
exhausted: false,
increment: 1
}
}
pub fn next(&mut self, mut size: Option<u32>) -> Option<u32> {
if size.is_none() {
size = match self.increment {
1 => None,
_ => Some(self.increment)
};
}
if !self.exhausted {
loop {
if let Some(n) = self.include.next(None, size) {
if self.is_valid(n) {
return Some(n);
}
} else {
self.exhausted = true;
break;
}
}
}
let size = size.unwrap_or(1);
loop {
if let Some(n) = self.oldest_reference() {
for i in 0..size {
if !self.is_valid(n + i) {
break;
}
}
for i in 0..size {
self.record_reference(n + i);
}
return Some(n);
} else {
return None;
}
}
}
fn is_valid(&self, num: u32) -> bool {
!self.exclude.contains(num) && !self.reserved.contains(num)
}
pub fn record_reference(&mut self, num: u32) {
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Time went backwards")
.as_nanos();
self.references.insert(num, now);
}
pub fn oldest_reference(&mut self) -> Option<u32> {
if self.references.is_empty() {
return None;
}
let (&oldest_num, _) = self.references
.iter()
.min_by_key(|&(_, ts)| ts)?;
Some(oldest_num)
}
pub fn iter(&self) -> impl Iterator<Item = u32> + '_ {
self.include.iter().filter(move |&num| !self.exclude.contains(num) && !self.reserved.contains(num))
}
}