use std::{fmt, marker::PhantomData};
type Index = u32;
pub struct Token<T> {
index: Index,
marker: PhantomData<T>,
}
impl<T> Clone for Token<T> {
fn clone(&self) -> Self {
Token {
index: self.index,
marker: self.marker,
}
}
}
impl<T> Copy for Token<T> {}
impl<T> PartialEq for Token<T> {
fn eq(&self, other: &Self) -> bool {
self.index == other.index
}
}
impl<T> Eq for Token<T> {}
impl<T> fmt::Debug for Token<T> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "Token({})", self.index)
}
}
impl<T> Token<T> {
#[cfg(test)]
pub const DUMMY: Self = Token {
index: !0,
marker: PhantomData,
};
pub(in crate::sr) fn new(index: Index) -> Self {
Token {
index,
marker: PhantomData,
}
}
pub fn index(&self) -> Index {
self.index
}
}
#[derive(Debug, Default)]
pub struct Storage<T> {
data: Vec<T>,
}
impl<T> Storage<T> {
pub fn new() -> Self {
Storage { data: Vec::new() }
}
pub fn append(&mut self, value: T) -> Token<T> {
let index = self.data.len() as Index;
self.data.push(value);
Token::new(index)
}
pub fn fetch_or_append(&mut self, value: T) -> Token<T>
where
T: PartialEq,
{
if let Some(index) = self.data.iter().position(|d| d == &value) {
Token::new(index as Index)
} else {
self.append(value)
}
}
}
impl<T> std::ops::Index<Token<T>> for Storage<T> {
type Output = T;
fn index(&self, token: Token<T>) -> &T {
&self.data[token.index as usize]
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn append_non_unique() {
let mut storage: Storage<f64> = Storage::new();
let t1 = storage.append(0.0);
let t2 = storage.append(0.0);
assert!(t1 != t2);
assert!(storage[t1] == storage[t2]);
}
#[test]
fn append_unique() {
let mut storage: Storage<f64> = Storage::new();
let t1 = storage.append(std::f64::NAN);
let t2 = storage.append(std::f64::NAN);
assert!(t1 != t2);
assert!(storage[t1] != storage[t2]);
}
#[test]
fn fetch_or_append_non_unique() {
let mut storage: Storage<f64> = Storage::new();
let t1 = storage.fetch_or_append(0.0);
let t2 = storage.fetch_or_append(0.0);
assert!(t1 == t2);
assert!(storage[t1] == storage[t2])
}
#[test]
fn fetch_or_append_unique() {
let mut storage: Storage<f64> = Storage::new();
let t1 = storage.fetch_or_append(std::f64::NAN);
let t2 = storage.fetch_or_append(std::f64::NAN);
assert!(t1 != t2);
assert!(storage[t1] != storage[t2]);
}
}