From 09eea547ba5aa1a5e3585c7d06197bd06fe7b45c Mon Sep 17 00:00:00 2001 From: chrysn Date: Tue, 28 Apr 2020 10:31:11 +0200 Subject: [PATCH 1/2] Allow more generic key types This moves the main key functionality into a trait, and makes Key<...> the default key used by Slots. This will later enable non-enforced keys, and could be extended to other forms of authentication of keys. --- src/lib.rs | 46 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 8870f50..f9571d6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -63,7 +63,14 @@ pub struct Key { _size_marker: PhantomData } -impl Key { +mod sealed { + pub trait Key { + fn new(idx: usize) -> Self; + fn index(&self) -> usize; + } +} + +impl sealed::Key for Key { fn new(idx: usize) -> Self { Self { index: idx, @@ -72,6 +79,15 @@ impl Key { } } + fn index(&self) -> usize { + self.index + } +} + +impl Key { + // 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 } @@ -80,14 +96,15 @@ impl Key { // 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 +pub struct Slots> where N: ArrayLength> + ArrayLength + Unsigned { items: GenericArray, N>, free_list: GenericArray, - free_count: usize + free_count: usize, + keys: PhantomData } -impl Slots +impl Slots where N: ArrayLength> + ArrayLength + Unsigned { pub fn new() -> Self { let size = N::to_usize(); @@ -95,7 +112,8 @@ impl Slots Self { items: GenericArray::default(), free_list: GenericArray::generate(|i: usize| size - i - 1), - free_count: size + free_count: size, + keys: PhantomData } } @@ -122,28 +140,28 @@ impl Slots } } - pub fn store(&mut self, item: IT) -> Result, IT> { + pub fn store(&mut self, item: IT) -> Result { 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 { - 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(&self, key: &Key, function: F) -> T where F: FnOnce(&IT) -> T { - match self.try_read(key.index, function) { + pub fn read(&self, key: &K, function: F) -> T where F: FnOnce(&IT) -> T { + match self.try_read(key.index(), function) { Some(t) => t, None => panic!() } @@ -156,8 +174,8 @@ impl Slots } } - pub fn modify(&mut self, key: &Key, function: F) -> T where F: FnOnce(&mut IT) -> T { - match self.items[key.index] { + pub fn modify(&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!() } From 0947ff8cd478ec3abe8d224f24a77a87b62b0fae Mon Sep 17 00:00:00 2001 From: chrysn Date: Tue, 28 Apr 2020 10:49:28 +0200 Subject: [PATCH 2/2] Allow usize as keys in unchecked slots --- src/lib.rs | 10 ++++++++++ tests/test.rs | 20 ++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index f9571d6..51199cc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -84,6 +84,16 @@ impl sealed::Key for Key { } } +impl sealed::Key for usize { + fn new(idx: usize) -> Self { + idx + } + + fn index(&self) -> usize { + *self + } +} + impl Key { // 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 diff --git a/tests/test.rs b/tests/test.rs index ea415e1..ff161a6 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -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();