Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 42 additions & 14 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,14 @@ pub struct Key<IT, N> {
_size_marker: PhantomData<N>
}

impl<IT, N> Key<IT, N> {
mod sealed {
pub trait Key {
fn new(idx: usize) -> Self;
fn index(&self) -> usize;
}
}

impl<IT, N> sealed::Key for Key<IT, N> {
fn new(idx: usize) -> Self {
Self {
index: idx,
Expand All @@ -72,6 +79,25 @@ impl<IT, N> Key<IT, N> {
}
}

fn index(&self) -> usize {
self.index
}
}

impl sealed::Key for usize {
fn new(idx: usize) -> Self {
idx
}

fn index(&self) -> usize {
*self
}
}

impl<IT, N> Key<IT, N> {
// Convenience duplicate to a) make it usable by applications without any `use slots::...::Key`
// method, and b) to spare everyone the hassle of having a public and a sealed trait around
// Key.
pub fn index(&self) -> usize {
self.index
}
Expand All @@ -80,22 +106,24 @@ impl<IT, N> Key<IT, N> {
// Data type that stores values and returns a key that can be used to manipulate
// the stored values.
// Values can be read by anyone but can only be modified using the key.
pub struct Slots<IT, N>
pub struct Slots<IT, N, K=Key<IT, N>>
where N: ArrayLength<Option<IT>> + ArrayLength<usize> + Unsigned {
items: GenericArray<Option<IT>, N>,
free_list: GenericArray<usize, N>,
free_count: usize
free_count: usize,
keys: PhantomData<K>
}

impl<IT, N> Slots<IT, N>
impl<IT, N, K: sealed::Key> Slots<IT, N, K>
where N: ArrayLength<Option<IT>> + ArrayLength<usize> + Unsigned {
pub fn new() -> Self {
let size = N::to_usize();

Self {
items: GenericArray::default(),
free_list: GenericArray::generate(|i: usize| size - i - 1),
free_count: size
free_count: size,
keys: PhantomData
}
}

Expand All @@ -122,28 +150,28 @@ impl<IT, N> Slots<IT, N>
}
}

pub fn store(&mut self, item: IT) -> Result<Key<IT, N>, IT> {
pub fn store(&mut self, item: IT) -> Result<K, IT> {
match self.alloc() {
Some(i) => {
self.items[i] = Some(item);
Ok(Key::new(i))
Ok(K::new(i))
}
None => Err(item)
}
}

pub fn take(&mut self, key: Key<IT, N>) -> IT {
match self.items[key.index].take() {
pub fn take(&mut self, key: K) -> IT {
match self.items[key.index()].take() {
Some(item) => {
self.free(key.index);
self.free(key.index());
item
}
None => panic!()
}
}

pub fn read<T, F>(&self, key: &Key<IT, N>, function: F) -> T where F: FnOnce(&IT) -> T {
match self.try_read(key.index, function) {
pub fn read<T, F>(&self, key: &K, function: F) -> T where F: FnOnce(&IT) -> T {
match self.try_read(key.index(), function) {
Some(t) => t,
None => panic!()
}
Expand All @@ -156,8 +184,8 @@ impl<IT, N> Slots<IT, N>
}
}

pub fn modify<T, F>(&mut self, key: &Key<IT, N>, function: F) -> T where F: FnOnce(&mut IT) -> T {
match self.items[key.index] {
pub fn modify<T, F>(&mut self, key: &K, function: F) -> T where F: FnOnce(&mut IT) -> T {
match self.items[key.index()] {
Some(ref mut item) => function(item),
None => panic!()
}
Expand Down
20 changes: 20 additions & 0 deletions tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,26 @@ fn key_can_be_used_to_read_value() {
assert_eq!(5, slots.read(&k1, |&w| w));
}

#[test]
fn uncheckedindex_can_be_used_to_read_value() {
let mut slots: Slots<_, U8, usize> = Slots::new();
let k1 = slots.store(5).unwrap();
let k2 = k1.clone();

assert_eq!(5, slots.read(&k2, |&w| w));
}

#[test]
#[should_panic(expected="explicit panic")]
fn uncheckedindex_can_be_used_to_panic() {
let mut slots: Slots<_, U8, usize> = Slots::new();
let k1 = slots.store(5).unwrap();
let k2 = k1.clone();

assert_eq!(5, slots.take(k1));
slots.take(k2);
}

#[test]
fn size_can_be_1() {
let mut slots: Slots<_, U1> = Slots::new();
Expand Down