wai_bindgen_wasmer/
table.rsuse std::convert::TryFrom;
use std::fmt;
use std::mem;
pub struct Table<T> {
elems: Vec<Slot<T>>,
next: usize,
}
#[derive(Debug)]
pub enum RemoveError {
NotAllocated,
}
enum Slot<T> {
Empty { next_empty: usize },
Full { item: Box<T> },
}
impl<T> Table<T> {
pub fn new() -> Table<T> {
Table {
elems: Vec::new(),
next: 0,
}
}
pub fn insert(&mut self, item: T) -> u32 {
if self.next == self.elems.len() {
let next_empty = self.next + 1;
self.elems.push(Slot::Empty { next_empty });
}
let index = self.next;
let ret = u32::try_from(index).unwrap();
self.next = match &self.elems[index] {
Slot::Empty { next_empty } => *next_empty,
Slot::Full { .. } => unreachable!(),
};
self.elems[index] = Slot::Full {
item: Box::new(item),
};
ret
}
pub fn get(&self, item: u32) -> Option<&T> {
let index = usize::try_from(item).unwrap();
match self.elems.get(index)? {
Slot::Empty { .. } => None,
Slot::Full { item } => Some(item),
}
}
pub fn remove(&mut self, item: u32) -> Result<T, RemoveError> {
let index = usize::try_from(item).unwrap();
let new_empty = Slot::Empty {
next_empty: self.next,
};
let slot = self.elems.get_mut(index).ok_or(RemoveError::NotAllocated)?;
match mem::replace(slot, new_empty) {
Slot::Full { item } => {
self.next = index;
Ok(*item)
}
Slot::Empty { next_empty } => {
*slot = Slot::Empty { next_empty };
Err(RemoveError::NotAllocated)
}
}
}
}
impl<T> Default for Table<T> {
fn default() -> Table<T> {
Table::new()
}
}
impl<T> fmt::Debug for Table<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Table")
.field("capacity", &self.elems.capacity())
.finish()
}
}
impl fmt::Display for RemoveError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
RemoveError::NotAllocated => f.write_str("invalid handle index"),
}
}
}
impl std::error::Error for RemoveError {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn simple() {
let mut table = Table::new();
assert_eq!(table.insert(0), 0);
assert_eq!(table.insert(100), 1);
assert_eq!(table.insert(200), 2);
assert_eq!(*table.get(0).unwrap(), 0);
assert_eq!(*table.get(1).unwrap(), 100);
assert_eq!(*table.get(2).unwrap(), 200);
assert!(table.get(100).is_none());
assert!(table.remove(0).is_ok());
assert!(table.get(0).is_none());
assert_eq!(table.insert(1), 0);
assert!(table.get(0).is_some());
table.get(1).unwrap();
assert!(table.remove(1).is_ok());
assert!(table.remove(1).is_err());
assert!(table.remove(2).is_ok());
assert!(table.remove(0).is_ok());
assert_eq!(table.insert(100), 0);
assert_eq!(table.insert(100), 2);
assert_eq!(table.insert(100), 1);
assert_eq!(table.insert(100), 3);
}
}