pub struct Prison<T> { /* private fields */ }Expand description
The single-threaded implementation of Prison
This struct uses an underlying Vec
It does this by using UnsafeCell to wrap its internals, a ref-counting usize on each element, and a master usize access-counter that are used to determine what cells (indexes) are currently being accessed to prevent violating Rust’s memory management rules. Each element also has a usize generation counter to determine if the value being requested was created in the same context it is being requested in.
Removing elements does not shift all elements that come after it like a normal Vec. Instead, it marks the element as “free”, meaning the value was deleted or removed. Subsequent inserts into the Prison will insert values into free spaces before they consider extending the Vec, minimizing reallocations when possible.
See the crate-level documentation or individual methods for more info
Implementations§
Source§impl<T> Prison<T>
impl<T> Prison<T>
Sourcepub fn new() -> Self
pub fn new() -> Self
Create a new Prison with the default allocation strategy (Vec::new())
Because Prison accepts values that may or may not be implement Copy, Clone, or Default and because indexes are simply marked as “free” when their values are removed from the Prison, a closure must be provided upon creation of a new prison that supplies it default values to replace the removed ones with safely (mem::replace()) without running into double-frees or use-after-frees or resorting to things like ManuallyDrop or MaybeUninit
Because re-allocating the internal Vec comes with many restrictions when accessing references to its elements, it is recommended to use Prison::with_capacity() with a suitable best-guess starting value rather than Prison::new()
§Example
let my_prison: Prison<u32> = Prison::new();
assert!(my_prison.vec_cap() < 100)Sourcepub fn with_capacity(size: usize) -> Self
pub fn with_capacity(size: usize) -> Self
Create a new Prison
Because Prison
Because re-allocating the internal Vec comes with many restrictions when accessing references to its elements, it is recommended to use Prison::with_capacity() with a suitable best-guess starting value rather than Prison::new()
§Example
let my_prison: Prison<u32> = Prison::with_capacity(1000);
assert!(my_prison.vec_cap() == 1000)Sourcepub fn vec_cap(&self) -> usize
pub fn vec_cap(&self) -> usize
Return the capacity of the underlying Vec
Capacity refers to the number of total spaces in memory reserved for the Vec
Because a Prison may have values that are free/deleted that are not counted withing the capacity of the Vec, this value should not be used to determine how many empty spots exist to add elements into the Prison
Sourcepub fn num_free(&self) -> usize
pub fn num_free(&self) -> usize
Return the number of spaces available for elements to be added to the Prison without reallocating more memory.
Sourcepub fn num_used(&self) -> usize
pub fn num_used(&self) -> usize
Return the number of spaces currently occupied by valid elements in the Prison
Sourcepub fn density(&self) -> f32
pub fn density(&self) -> f32
Return the ratio of used space to total space in the Prison
0.0 = 0% used, 1.0 = 100% used
Sourcepub fn insert(&self, value: T) -> Result<CellKey, AccessError>
pub fn insert(&self, value: T) -> Result<CellKey, AccessError>
Insert a value into the Prison and recieve a CellKey that can be used to reference it in the future
As long as there are sufficient free cells or vector capacity to do so,
you may insert() to the Prison while any of its elements have active references
§Example
let string_prison: Prison<String> = Prison::with_capacity(10);
let key_0 = string_prison.insert(String::from("Hello, "))?;
string_prison.visit_ref(key_0, |first_string| {
let key_1 = string_prison.insert(String::from("World!"))?;
string_prison.visit_ref(key_1, |second_string| {
let hello_world = format!("{}{}", first_string, second_string);
assert_eq!(hello_world, "Hello, World!");
Ok(())
});
Ok(())
});However, if the Prison is at maxumum capacity, attempting to insert()
during while there are active references to any element will cause the operation to fail and a
AccessError::InsertAtMaxCapacityWhileAValueIsReferenced to be returned
§Example
let string_prison: Prison<String> = Prison::with_capacity(1);
let key_0 = string_prison.insert(String::from("Hello, "))?;
string_prison.visit_ref(key_0, |first_string| {
assert!(string_prison.insert(String::from("World!")).is_err());
Ok(())
})?;Sourcepub fn insert_at(&self, idx: usize, value: T) -> Result<CellKey, AccessError>
pub fn insert_at(&self, idx: usize, value: T) -> Result<CellKey, AccessError>
§This operation has O(N) time complexity
Insert a value into the Prison at the specified index and recieve a CellKey that can be used to reference it in the future
The index must be within range of the underlying Vec AND must reference a space tagged as free/deleted.
§Example
let string_prison: Prison<String> = Prison::with_capacity(10);
let key_0 = string_prison.insert(String::from("Hello, "))?;
let key_1 = string_prison.insert(String::from("World!"))?;
string_prison.remove(key_1)?;
let key_1 = string_prison.insert_at(1, String::from("Rust!!"))?;
string_prison.visit_many_ref(&[key_0, key_1], |vals| {
let hello_world = format!("{}{}", vals[0], vals[1]);
assert_eq!(hello_world, "Hello, Rust!!");
Ok(())
})?;If the index is out of range the function will return an [AccessError::IndexOutOfRange(idx)], and if the index is not free/deleted, it will return an [AccessError::IndexIsNotFree(idx)]
§Example
let string_prison: Prison<String> = Prison::with_capacity(10);
let key_0 = string_prison.insert(String::from("Hello, "))?;
let key_1 = string_prison.insert(String::from("World!"))?;
assert!(string_prison.insert_at(1, String::from("Rust!!")).is_err());
assert!(string_prison.insert_at(10, String::from("Oops...")).is_err());Sourcepub fn overwrite(&self, idx: usize, value: T) -> Result<CellKey, AccessError>
pub fn overwrite(&self, idx: usize, value: T) -> Result<CellKey, AccessError>
Insert or overwrite a value in the Prison at the specified index and recieve a CellKey that can be used to reference it in the future
Similar to Prison::insert_at() but does not require the space be marked as free.
Note: Overwriting a value that isn’t marked as free will invalidate any CellKey that could have been used to reference it and cause a lookup using the old key(s) to return an [AccessError::ValueDeleted(idx, gen)]
§Example
let string_prison: Prison<String> = Prison::with_capacity(10);
let key_0 = string_prison.insert(String::from("Hello, "))?;
let key_1_a = string_prison.insert(String::from("World!"))?;
// string_prison.remove(key_1)?; // removal not needed
let key_1_b = string_prison.overwrite(1, String::from("Rust!!"))?;
string_prison.visit_many_ref(&[key_0, key_1_b], |vals| {
let hello_world = format!("{}{}", vals[0], vals[1]);
assert_eq!(hello_world, "Hello, Rust!!");
Ok(())
});
assert!(string_prison.visit_ref(key_1_a, |deleted_val| Ok(())).is_err());
assert!(string_prison.overwrite(10, String::from("Oops...")).is_err());Sourcepub fn remove(&self, key: CellKey) -> Result<T, AccessError>
pub fn remove(&self, key: CellKey) -> Result<T, AccessError>
Remove and return the element indexed by the provided CellKey
As long as the element doesn’t have an active reference you can .remove() it
§Example
let string_prison: Prison<String> = Prison::with_capacity(15);
let key_0 = string_prison.insert(String::from("Hello, "))?;
let key_1 = string_prison.insert(String::from("World!"))?;
let mut take_world = String::new();
string_prison.visit_ref(key_0, |hello| {
take_world = string_prison.remove(key_1)?;
Ok(())
})?;
assert_eq!(take_world, "World!");However, if the element does have an active reference, either from visit() or guard(),
remove() will return an [AccessError::RemoveWhileValueReferenced(idx)] with the index in question
§Example
let string_prison: Prison<String> = Prison::with_capacity(15);
let key_0 = string_prison.insert(String::from("Everything"))?;
string_prison.visit_ref(key_0, |everything| {
assert!(string_prison.remove(key_0).is_err());
Ok(())
})?;Sourcepub fn remove_idx(&self, idx: usize) -> Result<T, AccessError>
pub fn remove_idx(&self, idx: usize) -> Result<T, AccessError>
Remove and return the element at the specified index
Like remove() but disregards the generation counter
As long as the element doesnt have an active reference you can .remove_idx() it
§Example
let string_prison: Prison<String> = Prison::with_capacity(15);
string_prison.insert(String::from("Hello, "))?;
string_prison.insert(String::from("World!"))?;
let mut take_world = String::new();
string_prison.visit_ref_idx(0, |hello| {
take_world = string_prison.remove_idx(1)?;
Ok(())
})?;
assert_eq!(take_world, "World!");However, if the element does have an active reference, either from visit() or guard(),
.remove_idx() will return an [AccessError::RemoveWhileValueReferenced(idx)] with the index in question
§Example
let string_prison: Prison<String> = Prison::with_capacity(15);
string_prison.insert(String::from("Everything"))?;
string_prison.visit_ref_idx(0, |everything| {
assert!(string_prison.remove_idx(0).is_err());
Ok(())
})?;Sourcepub fn visit_mut<F>(
&self,
key: CellKey,
operation: F,
) -> Result<(), AccessError>
pub fn visit_mut<F>( &self, key: CellKey, operation: F, ) -> Result<(), AccessError>
Visit a single value in the Prison, obtaining a mutable reference to the value that is passed into a closure you provide.
You can only obtain a single mutable reference to an element at any given time, and cannot move the mutable reference out of the closure, meaning there is only one mutable reference to it at any time (and zero immutable references).
§Example
let u32_prison: Prison<u32> = Prison::new();
let key_0 = u32_prison.insert(42)?;
u32_prison.visit_mut(key_0, |mut_ref_42| {
*mut_ref_42 = 69; // nice
Ok(())
});§Errors
- [AccessError::ValueAlreadyMutablyReferenced(idx)] if element is already mutably referenced
- [AccessError::ValueStillImmutablyReferenced(idx)] if element has any number of immutable references
- [AccessError::IndexOutOfRange(idx)] if the CellKey index is out of range
- [AccessError::ValueDeleted(idx, gen)] if the cell is marked as free/deleted OR the CellKey generation doe not match
§Example
let u32_prison: Prison<u32> = Prison::new();
let key_0 = u32_prison.insert(42)?;
let key_1 = u32_prison.insert(69)?;
u32_prison.remove(key_1)?;
u32_prison.visit_mut(key_0, |mut_ref_42| {
assert!(u32_prison.visit_mut(key_0, |mut_ref_42_again| Ok(())).is_err());
assert!(u32_prison.visit_ref(key_0, |mut_ref_42_again| Ok(())).is_err());
assert!(u32_prison.visit_mut(CellKey::from_raw_parts(5, 5), |doesnt_exist| Ok(())).is_err());
assert!(u32_prison.visit_mut(key_1, |deleted| Ok(())).is_err());
Ok(())
})?;§Example
let u32_prison: Prison<u32> = Prison::new();
let key_0 = u32_prison.insert(42)?;
let mut try_to_take_the_ref: &mut u32 = &mut 0;
u32_prison.visit_mut(key_0, |mut_ref_42| {
// will not compile: (error[E0521]: borrowed data escapes outside of closure)
try_to_take_the_ref = mut_ref_42;
Ok(())
})?;Sourcepub fn visit_ref<F>(
&self,
key: CellKey,
operation: F,
) -> Result<(), AccessError>
pub fn visit_ref<F>( &self, key: CellKey, operation: F, ) -> Result<(), AccessError>
Visit a single value in the Prison, obtaining an immutable reference to the value that is passed into a closure you provide.
You obtain any number of simultaneous immutable references to an element, cannot obtain a mutable reference while any immutable references are active, and cannot move the immutable references out of the closure,
§Example
let u32_prison: Prison<u32> = Prison::new();
let key_0 = u32_prison.insert(42)?;
u32_prison.visit_ref(key_0, |ref_42_a| {
u32_prison.visit_ref(key_0, |ref_42_b| {
assert_eq!(*ref_42_a, *ref_42_b);
Ok(())
});
Ok(())
});§Errors
- [AccessError::ValueAlreadyMutablyReferenced(idx)] if element is already mutably referenced
- [AccessError::MaximumImmutableReferencesReached(idx)] if you created usize::MAX - 2 immutable references already
- [AccessError::IndexOutOfRange(idx)] if the CellKey index is out of range
- [AccessError::ValueDeleted(idx, gen)] if the cell is marked as free/deleted OR the CellKey generation doe not match
§Example
let u32_prison: Prison<u32> = Prison::new();
let key_0 = u32_prison.insert(42)?;
let key_1 = u32_prison.insert(69)?;
u32_prison.remove(key_1)?;
u32_prison.visit_ref(key_0, |ref_42| {
assert!(u32_prison.visit_mut(key_0, |mut_ref_42| Ok(())).is_err());
assert!(u32_prison.visit_ref(CellKey::from_raw_parts(5, 5), |doesnt_exist| Ok(())).is_err());
assert!(u32_prison.visit_ref(key_1, |deleted| Ok(())).is_err());
Ok(())
})?;§Example
let u32_prison: Prison<u32> = Prison::new();
let key_0 = u32_prison.insert(42)?;
let mut try_to_take_the_ref: & u32 = & 0;
u32_prison.visit_ref(key_0, |ref_42| {
// will not compile: (error[E0521]: borrowed data escapes outside of closure)
try_to_take_the_ref = ref_42;
Ok(())
})?;Sourcepub fn visit_mut_idx<F>(
&self,
idx: usize,
operation: F,
) -> Result<(), AccessError>
pub fn visit_mut_idx<F>( &self, idx: usize, operation: F, ) -> Result<(), AccessError>
Visit a single value in the Prison, obtaining a mutable reference to the value that is passed into a closure you provide.
Similar to visit_mut() but ignores the generation counter
You can only obtain a single mutable reference to an element at any given time, and cannot move the mutable reference out of the closure, meaning there is only one mutable reference to it at any time (and zero immutable references).
§Example
let u32_prison: Prison<u32> = Prison::new();
u32_prison.insert(42)?;
u32_prison.visit_mut_idx(0, |mut_ref_42| {
*mut_ref_42 = 69; // nice
Ok(())
});§Errors
- [AccessError::ValueAlreadyMutablyReferenced(idx)] if element is already mutably referenced
- [AccessError::ValueStillImmutablyReferenced(idx)] if element has any number of immutable references
- [AccessError::IndexOutOfRange(idx)] if the index is out of range
- [AccessError::ValueDeleted(idx, gen)] if the cell is marked as free/deleted
§Example
let u32_prison: Prison<u32> = Prison::new();
u32_prison.insert(42)?;
u32_prison.insert(69)?;
u32_prison.remove_idx(1)?;
u32_prison.visit_mut_idx(0, |mut_ref_42| {
assert!(u32_prison.visit_mut_idx(0, |mut_ref_42_again| Ok(())).is_err());
assert!(u32_prison.visit_ref_idx(0, |mut_ref_42_again| Ok(())).is_err());
assert!(u32_prison.visit_mut_idx(5, |doesnt_exist| Ok(())).is_err());
assert!(u32_prison.visit_mut_idx(1, |deleted| Ok(())).is_err());
Ok(())
})?;§Example
let u32_prison: Prison<u32> = Prison::new();
u32_prison.insert(42)?;
let mut try_to_take_the_ref: &mut u32 = &mut 0;
u32_prison.visit_mut_idx(0, |mut_ref_42| {
// will not compile: (error[E0521]: borrowed data escapes outside of closure)
try_to_take_the_ref = mut_ref_42;
Ok(())
})?;Sourcepub fn visit_ref_idx<F>(
&self,
idx: usize,
operation: F,
) -> Result<(), AccessError>
pub fn visit_ref_idx<F>( &self, idx: usize, operation: F, ) -> Result<(), AccessError>
Visit a single value in the Prison, obtaining an immutable reference to the value that is passed into a closure you provide.
Similar to visit_ref() but ignores the generation counter
You obtain any number of simultaneous immutable references to an element, cannot obtain a mutable reference while any immutable references are active, and cannot move the immutable references out of the closure,
§Example
let u32_prison: Prison<u32> = Prison::new();
u32_prison.insert(42)?;
u32_prison.visit_ref_idx(0, |ref_42_a| {
u32_prison.visit_ref_idx(0, |ref_42_b| {
assert_eq!(*ref_42_a, *ref_42_b);
Ok(())
});
Ok(())
});§Errors
- [AccessError::ValueAlreadyMutablyReferenced(idx)] if element is already mutably referenced
- [AccessError::MaximumImmutableReferencesReached(idx)] if you created usize::MAX - 2 immutable references already
- [AccessError::IndexOutOfRange(idx)] if the CellKey index is out of range
- [AccessError::ValueDeleted(idx, gen)] if the cell is marked as free/deleted
§Example
let u32_prison: Prison<u32> = Prison::new();
u32_prison.insert(42)?;
u32_prison.insert(69)?;
u32_prison.remove_idx(1)?;
u32_prison.visit_ref_idx(0, |ref_42| {
assert!(u32_prison.visit_mut_idx(0, |mut_ref_42| Ok(())).is_err());
assert!(u32_prison.visit_ref_idx(5, |doesnt_exist| Ok(())).is_err());
assert!(u32_prison.visit_ref_idx(1, |deleted| Ok(())).is_err());
Ok(())
})?;§Example
let u32_prison: Prison<u32> = Prison::new();
u32_prison.insert(42)?;
let mut try_to_take_the_ref: & u32 = & 0;
u32_prison.visit_ref_idx(0, |ref_42| {
// will not compile: (error[E0521]: borrowed data escapes outside of closure)
try_to_take_the_ref = ref_42;
Ok(())
})?;Sourcepub fn visit_many_mut<F>(
&self,
keys: &[CellKey],
operation: F,
) -> Result<(), AccessError>
pub fn visit_many_mut<F>( &self, keys: &[CellKey], operation: F, ) -> Result<(), AccessError>
Visit many values in the Prison at the same time, obtaining a mutable reference to all of them in the same closure and in the same order they were requested.
While you can obtain multiple unrelated mutable references simultaneously, you can only obtain a single mutable reference to the same element at any given time, and cannot move the mutable reference out of the closure, meaning there is only one mutable reference to it at any time (and zero immutable references).
§Example
let u32_prison: Prison<u32> = Prison::new();
let key_0 = u32_prison.insert(42)?;
let key_1 = u32_prison.insert(43)?;
let key_2 = u32_prison.insert(44)?;
let key_3 = u32_prison.insert(45)?;
u32_prison.visit_many_mut(&[key_3, key_2, key_1, key_0], |first_four_reversed| {
assert_eq!(*first_four_reversed[0], 45);
assert_eq!(*first_four_reversed[1], 44);
assert_eq!(*first_four_reversed[2], 43);
assert_eq!(*first_four_reversed[3], 42);
Ok(())
})?;Just like .visit_mut(), any particular element can only have one mutable reference,
but as long as the elements requested don’t overlap you may make nested
visit() or guard() calls
§Example
let u32_prison: Prison<u32> = Prison::new();
let key_0 = u32_prison.insert(42)?;
let key_1 = u32_prison.insert(43)?;
let key_2 = u32_prison.insert(44)?;
let key_3 = u32_prison.insert(45)?;
u32_prison.visit_many_mut(&[key_0, key_2], |evens| {
u32_prison.visit_many_mut(&[key_1, key_3], |odds| {
assert_eq!(*evens[1], 44);
assert_eq!(*odds[1], 45);
Ok(())
});
Ok(())
});§Errors
- [AccessError::ValueAlreadyMutablyReferenced(idx)] if any element is already mutably referenced
- [AccessError::ValueStillImmutablyReferenced(idx)] if any element has any number of immutable references
- [AccessError::IndexOutOfRange(idx)] if any index is out of range
- [AccessError::ValueDeleted(idx, gen)] if any cell is marked as free/deleted OR the CellKey generation doesnt match
§Example
let u32_prison: Prison<u32> = Prison::new();
let key_0 = u32_prison.insert(42)?;
let key_1 = u32_prison.insert(43)?;
let key_2 = u32_prison.insert(44)?;
let key_3 = u32_prison.insert(45)?;
u32_prison.remove(key_1)?;
let key_4 = CellKey::from_raw_parts(4, 1);
assert!(u32_prison.visit_many_mut(&[key_0, key_0], |double_key_zero| Ok(())).is_err());
assert!(u32_prison.visit_many_mut(&[key_1, key_2, key_3], |key_1_removed| Ok(())).is_err());
assert!(u32_prison.visit_many_mut(&[key_2, key_3, key_4], |key_4_invalid| Ok(())).is_err());Sourcepub fn visit_many_ref<F>(
&self,
keys: &[CellKey],
operation: F,
) -> Result<(), AccessError>
pub fn visit_many_ref<F>( &self, keys: &[CellKey], operation: F, ) -> Result<(), AccessError>
Visit many values in the Prison at the same time, obtaining an immutable reference to all of them in the same closure and in the same order they were requested.
As long as the element does not have any mutable references, you can obtain multiple immutable references to the same element
§Example
let u32_prison: Prison<u32> = Prison::new();
let key_0 = u32_prison.insert(42)?;
let key_1 = u32_prison.insert(43)?;
let key_2 = u32_prison.insert(44)?;
let key_3 = u32_prison.insert(45)?;
u32_prison.visit_many_ref(&[key_3, key_2, key_1, key_0], |first_four_reversed| {
assert_eq!(*first_four_reversed[0], 45);
assert_eq!(*first_four_reversed[1], 44);
assert_eq!(*first_four_reversed[2], 43);
assert_eq!(*first_four_reversed[3], 42);
u32_prison.visit_many_ref(&[key_0, key_1, key_2, key_3], |first_four_original| {
assert_eq!(*first_four_original[0], 42);
assert_eq!(*first_four_original[1], 43);
assert_eq!(*first_four_original[2], 44);
assert_eq!(*first_four_original[3], 45);
Ok(())
})?;
Ok(())
})?;Just like .visit_ref(), any particular element can have multile immutable references to
it as long as it has no mutable, meaning you can make nested
visit() or guard() calls to the same element if desired
§Example
let u32_prison: Prison<u32> = Prison::new();
let key_0 = u32_prison.insert(42)?;
let key_1 = u32_prison.insert(43)?;
let key_2 = u32_prison.insert(44)?;
let key_3 = u32_prison.insert(45)?;
u32_prison.visit_many_ref(&[key_0, key_2], |evens| {
u32_prison.visit_many_ref(&[key_1, key_3], |odds| {
assert_eq!(*evens[1], 44);
assert_eq!(*odds[1], 45);
assert!(u32_prison.visit_many_ref(&[key_0, key_1, key_2, key_3], |all| Ok(())).is_ok());
Ok(())
});
Ok(())
});§Errors
- [AccessError::ValueAlreadyMutablyReferenced(idx)] if any element is already mutably referenced
- [AccessError::MaximumImmutableReferencesReached(idx)] if you created usize::MAX - 2 immutable references to any element
- [AccessError::IndexOutOfRange(idx)] if any index is out of range
- [AccessError::ValueDeleted(idx, gen)] if any cell is marked as free/deleted OR if the CellKey generation doesn’t match
§Example
let u32_prison: Prison<u32> = Prison::new();
let key_0 = u32_prison.insert(42)?;
let key_1 = u32_prison.insert(43)?;
let key_2 = u32_prison.insert(44)?;
let key_3 = u32_prison.insert(45)?;
u32_prison.remove(key_1)?;
let key_4 = CellKey::from_raw_parts(4, 1);
u32_prison.visit_mut(key_0, |mut_0| {
assert!(u32_prison.visit_many_ref(&[key_0], |zero_already_mut| Ok(())).is_err());
assert!(u32_prison.visit_many_ref(&[key_1, key_2, key_3], |key_1_removed| Ok(())).is_err());
assert!(u32_prison.visit_many_ref(&[key_2, key_3, key_4], |key_4_invalid| Ok(())).is_err());
Ok(())
})?;Sourcepub fn visit_many_mut_idx<F>(
&self,
indexes: &[usize],
operation: F,
) -> Result<(), AccessError>
pub fn visit_many_mut_idx<F>( &self, indexes: &[usize], operation: F, ) -> Result<(), AccessError>
Visit many values in the Prison at the same time, obtaining a mutable reference to all of them in the same closure and in the same order they were requested.
Similar to visit_many_mut() but ignores the generation counter
While you can obtain multiple unrelated mutable references simultaneously, you can only obtain a single mutable reference to the same element at any given time, and cannot move the mutable reference out of the closure, meaning there is only one mutable reference to it at any time (and zero immutable references).
§Example
let u32_prison: Prison<u32> = Prison::new();
u32_prison.insert(42)?;
u32_prison.insert(43)?;
u32_prison.insert(44)?;
u32_prison.insert(45)?;
u32_prison.visit_many_mut_idx(&[3, 2, 1, 0], |first_four_reversed| {
assert_eq!(*first_four_reversed[0], 45);
assert_eq!(*first_four_reversed[1], 44);
assert_eq!(*first_four_reversed[2], 43);
assert_eq!(*first_four_reversed[3], 42);
Ok(())
})?;Just like .visit_mut_idx(), any particular element can only have one mutable reference,
but as long as the elements requested don’t overlap you may make nested
visit() or guard() calls
§Example
let u32_prison: Prison<u32> = Prison::new();
u32_prison.insert(42)?;
u32_prison.insert(43)?;
u32_prison.insert(44)?;
u32_prison.insert(45)?;
u32_prison.visit_many_mut_idx(&[0, 2], |evens| {
u32_prison.visit_many_mut_idx(&[1, 3], |odds| {
assert_eq!(*evens[1], 44);
assert_eq!(*odds[1], 45);
Ok(())
});
Ok(())
});§Errors
- [AccessError::ValueAlreadyMutablyReferenced(idx)] if any element is already mutably referenced
- [AccessError::ValueStillImmutablyReferenced(idx)] if any element has any number of immutable references
- [AccessError::IndexOutOfRange(idx)] if any index is out of range
- [AccessError::ValueDeleted(idx, gen)] if any cell is marked as free/deleted
§Example
let u32_prison: Prison<u32> = Prison::new();
u32_prison.insert(42)?;
u32_prison.insert(43)?;
u32_prison.insert(44)?;
u32_prison.insert(45)?;
u32_prison.remove_idx(1)?;
assert!(u32_prison.visit_many_mut_idx(&[0, 0], |double_idx_zero| Ok(())).is_err());
assert!(u32_prison.visit_many_mut_idx(&[1, 2, 3], |idx_1_removed| Ok(())).is_err());
assert!(u32_prison.visit_many_mut_idx(&[2, 3, 4], |idx_4_invalid| Ok(())).is_err());Sourcepub fn visit_many_ref_idx<F>(
&self,
indexes: &[usize],
operation: F,
) -> Result<(), AccessError>
pub fn visit_many_ref_idx<F>( &self, indexes: &[usize], operation: F, ) -> Result<(), AccessError>
Visit many values in the Prison at the same time, obtaining an immutable reference to all of them in the same closure and in the same order they were requested.
Similar to visit_many_ref() but ignores the generation counter
As long as the element does not have any mutable references, you can obtain multiple immutable references to the same element
§Example
let u32_prison: Prison<u32> = Prison::new();
u32_prison.insert(42)?;
u32_prison.insert(43)?;
u32_prison.insert(44)?;
u32_prison.insert(45)?;
u32_prison.visit_many_ref_idx(&[3, 2, 1, 0], |first_four_reversed| {
assert_eq!(*first_four_reversed[0], 45);
assert_eq!(*first_four_reversed[1], 44);
assert_eq!(*first_four_reversed[2], 43);
assert_eq!(*first_four_reversed[3], 42);
u32_prison.visit_many_ref_idx(&[0, 1, 2, 3], |first_four_original| {
assert_eq!(*first_four_original[0], 42);
assert_eq!(*first_four_original[1], 43);
assert_eq!(*first_four_original[2], 44);
assert_eq!(*first_four_original[3], 45);
Ok(())
})?;
Ok(())
})?;Just like .visit_ref_idx(), any particular element can have multiple immutable references to
it as long as it has no mutable references, meaning you can make nested
visit() or guard() calls to the same element if desired
§Example
let u32_prison: Prison<u32> = Prison::new();
u32_prison.insert(42)?;
u32_prison.insert(43)?;
u32_prison.insert(44)?;
u32_prison.insert(45)?;
u32_prison.visit_many_ref_idx(&[0, 2], |evens| {
u32_prison.visit_many_ref_idx(&[1, 3], |odds| {
assert_eq!(*evens[1], 44);
assert_eq!(*odds[1], 45);
assert!(u32_prison.visit_many_ref_idx(&[0, 1, 2, 3], |all| Ok(())).is_ok());
Ok(())
});
Ok(())
});§Errors
- [AccessError::ValueAlreadyMutablyReferenced(idx)] if any element is already mutably referenced
- [AccessError::MaximumImmutableReferencesReached(idx)] if you created usize::MAX - 2 immutable references to any element
- [AccessError::IndexOutOfRange(idx)] if any index is out of range
- [AccessError::ValueDeleted(idx, gen)] if any cell is marked as free/deleted
§Example
let u32_prison: Prison<u32> = Prison::new();
u32_prison.insert(42)?;
u32_prison.insert(43)?;
u32_prison.insert(44)?;
u32_prison.insert(45)?;
u32_prison.remove_idx(1)?;
u32_prison.visit_mut_idx(0, |mut_0| {
assert!(u32_prison.visit_many_ref_idx(&[0], |zero_already_mut| Ok(())).is_err());
assert!(u32_prison.visit_many_ref_idx(&[1, 2, 3], |idx_1_removed| Ok(())).is_err());
assert!(u32_prison.visit_many_ref_idx(&[2, 3, 4], |idx_4_invalid| Ok(())).is_err());
Ok(())
})?;Sourcepub fn visit_slice_mut<R, F>(
&self,
range: R,
operation: F,
) -> Result<(), AccessError>
pub fn visit_slice_mut<R, F>( &self, range: R, operation: F, ) -> Result<(), AccessError>
Visit a slice of values in the Prison at the same time, obtaining a mutable reference to all of them in the same closure.
Internally this is strictly identical to passing Prison::visit_many_mut_idx() a list of all indexes in the slice range, and is subject to all the same restrictions and errors
§Example
let u32_prison: Prison<u32> = Prison::new();
u32_prison.insert(42)?;
u32_prison.insert(43)?;
u32_prison.insert(44)?;
u32_prison.insert(45)?;
u32_prison.insert(46)?;
u32_prison.visit_slice_mut(2..5, |last_three| {
assert_eq!(*last_three[0], 44);
assert_eq!(*last_three[1], 45);
assert_eq!(*last_three[2], 46);
Ok(())
});Any standard Range
§Example
let u32_prison: Prison<u32> = Prison::new();
u32_prison.insert(42)?;
u32_prison.insert(43)?;
u32_prison.insert(44)?;
u32_prison.insert(45)?;
u32_prison.insert(46)?;
assert!(u32_prison.visit_slice_mut(2..5, |last_three| Ok(())).is_ok());
assert!(u32_prison.visit_slice_mut(2..=4, |also_last_three| Ok(())).is_ok());
assert!(u32_prison.visit_slice_mut(2.., |again_last_three| Ok(())).is_ok());
assert!(u32_prison.visit_slice_mut(..3, |first_three| Ok(())).is_ok());
assert!(u32_prison.visit_slice_mut(..=3, |first_four| Ok(())).is_ok());
assert!(u32_prison.visit_slice_mut(.., |all| Ok(())).is_ok());
u32_prison.remove_idx(2)?;
assert!(u32_prison.visit_slice_mut(.., |all| Ok(())).is_err());See Prison::visit_many_mut_idx() for more info
Sourcepub fn visit_slice_ref<R, F>(
&self,
range: R,
operation: F,
) -> Result<(), AccessError>
pub fn visit_slice_ref<R, F>( &self, range: R, operation: F, ) -> Result<(), AccessError>
Visit a slice of values in the Prison at the same time, obtaining an immutable reference to all of them in the same closure.
Internally this is strictly identical to passing Prison::visit_many_ref_idx() a list of all indexes in the slice range, and is subject to all the same restrictions and errors
§Example
let u32_prison: Prison<u32> = Prison::new();
u32_prison.insert(42)?;
u32_prison.insert(43)?;
u32_prison.insert(44)?;
u32_prison.insert(45)?;
u32_prison.insert(46)?;
u32_prison.visit_slice_ref(2..5, |last_three| {
assert_eq!(*last_three[0], 44);
assert_eq!(*last_three[1], 45);
assert_eq!(*last_three[2], 46);
u32_prison.visit_slice_ref(0..3, |first_three| {
assert_eq!(*first_three[0], 42);
assert_eq!(*first_three[1], 43);
assert_eq!(*first_three[2], 44);
Ok(())
});
Ok(())
});Any standard Range
§Example
let u32_prison: Prison<u32> = Prison::new();
u32_prison.insert(42)?;
u32_prison.insert(43)?;
u32_prison.insert(44)?;
u32_prison.insert(45)?;
u32_prison.insert(46)?;
assert!(u32_prison.visit_slice_ref(2..5, |last_three| Ok(())).is_ok());
assert!(u32_prison.visit_slice_ref(2..=4, |also_last_three| Ok(())).is_ok());
assert!(u32_prison.visit_slice_ref(2.., |again_last_three| Ok(())).is_ok());
assert!(u32_prison.visit_slice_ref(..3, |first_three| Ok(())).is_ok());
assert!(u32_prison.visit_slice_ref(..=3, |first_four| Ok(())).is_ok());
assert!(u32_prison.visit_slice_ref(.., |all| Ok(())).is_ok());
u32_prison.remove_idx(2)?;
assert!(u32_prison.visit_slice_ref(.., |all| Ok(())).is_err());See Prison::visit_many_ref_idx() for more info
Sourcepub fn guard_mut<'a>(
&'a self,
key: CellKey,
) -> Result<PrisonValueMut<'a, T>, AccessError>
pub fn guard_mut<'a>( &'a self, key: CellKey, ) -> Result<PrisonValueMut<'a, T>, AccessError>
Return a PrisonValueMut that contains a mutable reference to the element and wraps it in guarding data that automatically frees its reference count it when it goes out of scope.
PrisonValueMut
As long as the PrisonValueMut remains in scope, the element where it’s value resides in the Prison will remain marked as mutably referenced and unable to be referenced a second time. You can manually drop the PrisonValueMut out of scope by passing it as the first parameter to the function [PrisonValueMut::unguard(p_val_mut)]
§Example
let prison: Prison<u32> = Prison::new();
let key_0 = prison.insert(10)?;
let mut grd_0 = prison.guard_mut(key_0)?;
assert_eq!(*grd_0, 10);
*grd_0 = 20;
PrisonValueMut::unguard(grd_0);
prison.visit_ref(key_0, |val_0| {
assert_eq!(*val_0, 20);
Ok(())
});§Errors
- [AccessError::ValueAlreadyMutablyReferenced(idx)] if element is already mutably referenced
- [AccessError::ValueStillImmutablyReferenced(idx)] if element has any number of immutable references
- [AccessError::IndexOutOfRange(idx)] if the CellKey index is out of range
- [AccessError::ValueDeleted(idx, gen)] if the cell is marked as free/deleted OR the CellKey generation does not match
§Example
let prison: Prison<u32> = Prison::with_capacity(2);
let key_0 = prison.insert(10)?;
let key_1_a = prison.insert(20)?;
let key_out_of_bounds = CellKey::from_raw_parts(10, 0);
prison.remove(key_1_a)?;
let key_1_b = prison.insert(30)?;
let mut grd_0 = prison.guard_mut(key_0)?;
assert!(prison.guard_mut(key_0).is_err());
assert!(prison.guard_mut(key_out_of_bounds).is_err());
assert!(prison.guard_mut(key_1_a).is_err());Sourcepub fn guard_ref<'a>(
&'a self,
key: CellKey,
) -> Result<PrisonValueRef<'a, T>, AccessError>
pub fn guard_ref<'a>( &'a self, key: CellKey, ) -> Result<PrisonValueRef<'a, T>, AccessError>
Return a PrisonValueRef that contains an immutable reference to the element and wraps it in guarding data that automatically decrements its reference count it when it goes out of scope.
PrisonValueRef
As long as the PrisonValueRef remains in scope, the element where it’s value resides in the Prison will remain marked as immutably referenced and unable to be mutably referenced. You can manually drop the PrisonValueRef out of scope by passing it as the first parameter to the function [PrisonValueRef::unguard(p_val_ref)]
§Example
let prison: Prison<u32> = Prison::new();
let key_0 = prison.insert(10)?;
let grd_0 = prison.guard_ref(key_0)?;
assert_eq!(*grd_0, 10);
prison.visit_ref(key_0, |val_0| {
assert_eq!(*val_0, 10);
Ok(())
});
assert_eq!(*grd_0, 10);
PrisonValueRef::unguard(grd_0);§Errors
- [AccessError::ValueAlreadyMutablyReferenced(idx)] if element is already mutably referenced
- [AccessError::MaximumImmutableReferencesReached(idx)] if you created usize::MAX - 2 immutable references already
- [AccessError::IndexOutOfRange(idx)] if the CellKey index is out of range
- [AccessError::ValueDeleted(idx, gen)] if the cell is marked as free/deleted OR the CellKey generation doe not match
§Example
let prison: Prison<u32> = Prison::with_capacity(2);
let key_0 = prison.insert(10)?;
let key_1_a = prison.insert(20)?;
let key_out_of_bounds = CellKey::from_raw_parts(10, 0);
prison.remove(key_1_a)?;
let key_1_b = prison.insert(30)?;
let grd_0 = prison.guard_ref(key_0)?;
assert!(prison.guard_mut(key_0).is_err());
assert!(prison.guard_ref(key_out_of_bounds).is_err());
assert!(prison.guard_ref(key_1_a).is_err());Sourcepub fn guard_mut_idx<'a>(
&'a self,
idx: usize,
) -> Result<PrisonValueMut<'a, T>, AccessError>
pub fn guard_mut_idx<'a>( &'a self, idx: usize, ) -> Result<PrisonValueMut<'a, T>, AccessError>
Return a PrisonValueMut that contains a mutable reference to the element and wraps it in guarding data that automatically frees its reference count it when it goes out of scope.
Smilar to guard_mut() but ignores the generation counter
PrisonValueMut
As long as the PrisonValueMut remains in scope, the element where it’s value resides in the Prison will remain marked as mutably referenced and unable to be referenced a second time. You can manually drop the PrisonValueMut out of scope by passing it as the first parameter to the function [PrisonValueMut::unguard(p_val_mut)]
§Example
let prison: Prison<u32> = Prison::new();
prison.insert(10)?;
let mut grd_0 = prison.guard_mut_idx(0)?;
assert_eq!(*grd_0, 10);
*grd_0 = 20;
PrisonValueMut::unguard(grd_0);
prison.visit_ref_idx(0, |val_0| {
assert_eq!(*val_0, 20);
Ok(())
});§Errors
- [AccessError::ValueAlreadyMutablyReferenced(idx)] if element is already mutably referenced
- [AccessError::ValueStillImmutablyReferenced(idx)] if element has any number of immutable references
- [AccessError::IndexOutOfRange(idx)] if the CellKey index is out of range
- [AccessError::ValueDeleted(idx, gen)] if the cell is marked as free/deleted
§Example
let prison: Prison<u32> = Prison::with_capacity(2);
prison.insert(10)?;
prison.insert(20)?;
prison.remove_idx(1)?;
let mut grd_0 = prison.guard_mut_idx(0)?;
assert!(prison.guard_mut_idx(0).is_err());
assert!(prison.guard_mut_idx(5).is_err());
assert!(prison.guard_mut_idx(1).is_err());Sourcepub fn guard_ref_idx<'a>(
&'a self,
idx: usize,
) -> Result<PrisonValueRef<'a, T>, AccessError>
pub fn guard_ref_idx<'a>( &'a self, idx: usize, ) -> Result<PrisonValueRef<'a, T>, AccessError>
Return a PrisonValueRef that contains an immutable reference to the element and wraps it in guarding data that automatically decrements its reference count it when it goes out of scope.
Similar to guard_ref() but ignores the generation counter
PrisonValueRef
As long as the PrisonValueRef remains in scope, the element where it’s value resides in the Prison will remain marked as immutably referenced and unable to be mutably referenced. You can manually drop the PrisonValueRef out of scope by passing it as the first parameter to the function [PrisonValueRef::unguard(p_val_ref)]
§Example
let prison: Prison<u32> = Prison::new();
prison.insert(10)?;
let grd_0 = prison.guard_ref_idx(0)?;
assert_eq!(*grd_0, 10);
prison.visit_ref_idx(0, |val_0| {
assert_eq!(*val_0, 10);
Ok(())
});
assert_eq!(*grd_0, 10);
PrisonValueRef::unguard(grd_0);§Errors
- [AccessError::ValueAlreadyMutablyReferenced(idx)] if element is already mutably referenced
- [AccessError::MaximumImmutableReferencesReached(idx)] if you created usize::MAX - 2 immutable references already
- [AccessError::IndexOutOfRange(idx)] if the CellKey index is out of range
- [AccessError::ValueDeleted(idx, gen)] if the cell is marked as free/deleted OR the CellKey generation doe not match
§Example
let prison: Prison<u32> = Prison::with_capacity(2);
prison.insert(10)?;
prison.insert(20)?;
prison.remove_idx(1)?;
let grd_0 = prison.guard_ref_idx(0)?;
assert!(prison.guard_mut_idx(0).is_err());
assert!(prison.guard_ref_idx(5).is_err());
assert!(prison.guard_ref_idx(1).is_err());Sourcepub fn guard_many_mut<'a>(
&'a self,
keys: &[CellKey],
) -> Result<PrisonSliceMut<'a, T>, AccessError>
pub fn guard_many_mut<'a>( &'a self, keys: &[CellKey], ) -> Result<PrisonSliceMut<'a, T>, AccessError>
Return a PrisonSliceMut that marks all the elements as mutably referenced and wraps them in guarding data that automatically frees their mutable reference counts when it goes out of range.
PrisonSliceMut
As long as the PrisonSliceMut remains in scope, the elements where it’s values reside in the Prison will remain marked as mutably referenced and unable to be referenced a second time. You can manually drop the PrisonSliceMut out of scope by passing it as the first parameter to the function [PrisonSliceMut::unguard(p_sli_mut)]
§Example
let prison: Prison<u32> = Prison::new();
let key_0 = prison.insert(10)?;
let key_1 = prison.insert(20)?;
let key_2 = prison.insert(30)?;
let mut grd_0_1_2 = prison.guard_many_mut(&[key_0, key_1, key_2])?;
assert_eq!(*grd_0_1_2[0], 10);
*grd_0_1_2[0] = 20;
PrisonSliceMut::unguard(grd_0_1_2);
prison.visit_many_ref(&[key_0, key_1, key_2], |vals_0_1_2| {
assert_eq!(*vals_0_1_2[0], 20);
Ok(())
});§Errors
- [AccessError::ValueAlreadyMutablyReferenced(idx)] if any element is already mutably referenced
- [AccessError::ValueStillImmutablyReferenced(idx)] if any element has any number of immutable references
- [AccessError::IndexOutOfRange(idx)] if any index is out of range
- [AccessError::ValueDeleted(idx, gen)] if any cell is marked as free/deleted OR the CellKey generation doesnt match
§Example
let prison: Prison<u32> = Prison::new();
let key_0 = prison.insert(10)?;
let key_1 = prison.insert(20)?;
let key_2 = prison.insert(30)?;
let key_4_a = prison.insert(40)?;
prison.remove(key_4_a)?;
let key_4_b = prison.insert(44)?;
let key_out_of_bounds = CellKey::from_raw_parts(10, 1);
let mut grd_0_1_2 = prison.guard_many_mut(&[key_0, key_1, key_2])?;
assert!(prison.guard_many_mut(&[key_0, key_1, key_2, key_4_b]).is_err());
assert!(prison.guard_many_mut(&[key_out_of_bounds]).is_err());
assert!(prison.guard_many_mut(&[key_4_a]).is_err());Sourcepub fn guard_many_ref<'a>(
&'a self,
keys: &[CellKey],
) -> Result<PrisonSliceRef<'a, T>, AccessError>
pub fn guard_many_ref<'a>( &'a self, keys: &[CellKey], ) -> Result<PrisonSliceRef<'a, T>, AccessError>
Return a PrisonSliceRef that marks all the elements as immutably referenced and wraps them in guarding data that automatically decreases their immutable reference counts when it goes out of range.
PrisonSliceRef
As long as the PrisonSliceRef remains in scope, the elements where it’s values reside in the Prison will remain marked as immutably referenced and unable to be mutably referenced. You can manually drop the PrisonSliceRef out of scope by passing it as the first parameter to the function [PrisonSliceRef::unguard(p_sli_ref)]
§Example
let prison: Prison<u32> = Prison::new();
let key_0 = prison.insert(10)?;
let key_1 = prison.insert(20)?;
let key_2 = prison.insert(30)?;
let mut grd_0_1_2 = prison.guard_many_ref(&[key_0, key_1, key_2])?;
assert_eq!(*grd_0_1_2[0], 10);
prison.visit_many_ref(&[key_0, key_1, key_2], |vals_0_1_2| {
assert_eq!(*vals_0_1_2[0], 10);
Ok(())
});
PrisonSliceRef::unguard(grd_0_1_2);§Errors
- [AccessError::ValueAlreadyMutablyReferenced(idx)] if any element is already mutably referenced
- [AccessError::MaximumImmutableReferencesReached(idx)] if you created usize::MAX - 2 immutable references to any element
- [AccessError::IndexOutOfRange(idx)] if any index is out of range
- [AccessError::ValueDeleted(idx, gen)] if any cell is marked as free/deleted OR if the CellKey generation doesn’t match
§Example
let prison: Prison<u32> = Prison::new();
let key_0 = prison.insert(10)?;
let key_1 = prison.insert(20)?;
let key_2 = prison.insert(30)?;
let key_4_a = prison.insert(40)?;
prison.remove(key_4_a)?;
let key_4_b = prison.insert(44)?;
let key_out_of_bounds = CellKey::from_raw_parts(10, 1);
let grd_0_1_2 = prison.guard_many_ref(&[key_0, key_1, key_2])?;
assert!(prison.guard_many_mut(&[key_0]).is_err());
assert!(prison.guard_many_ref(&[key_out_of_bounds]).is_err());
assert!(prison.guard_many_ref(&[key_4_a]).is_err());Sourcepub fn guard_many_mut_idx<'a>(
&'a self,
indexes: &[usize],
) -> Result<PrisonSliceMut<'a, T>, AccessError>
pub fn guard_many_mut_idx<'a>( &'a self, indexes: &[usize], ) -> Result<PrisonSliceMut<'a, T>, AccessError>
Return a PrisonSliceMut that marks all the elements as mutably referenced and wraps them in guarding data that automatically frees their mutable reference counts when it goes out of range.
Similar to guard_many_mut() but ignores the generation counter
PrisonSliceMut
As long as the PrisonSliceMut remains in scope, the elements where it’s values reside in the Prison will remain marked as mutably referenced and unable to be referenced a second time. You can manually drop the PrisonSliceMut out of scope by passing it as the first parameter to the function [PrisonSliceMut::unguard(p_sli_mut)]
§Example
let prison: Prison<u32> = Prison::new();
prison.insert(10)?;
prison.insert(20)?;
prison.insert(30)?;
let mut grd_0_1_2 = prison.guard_many_mut_idx(&[0, 1, 2])?;
assert_eq!(*grd_0_1_2[0], 10);
*grd_0_1_2[0] = 20;
PrisonSliceMut::unguard(grd_0_1_2);
prison.visit_many_ref_idx(&[0, 1, 2], |vals_0_1_2| {
assert_eq!(*vals_0_1_2[0], 20);
Ok(())
});§Errors
- [AccessError::ValueAlreadyMutablyReferenced(idx)] if any element is already mutably referenced
- [AccessError::ValueStillImmutablyReferenced(idx)] if any element has any number of immutable references
- [AccessError::IndexOutOfRange(idx)] if any index is out of range
- [AccessError::ValueDeleted(idx, gen)] if any cell is marked as free/deleted
§Example
let prison: Prison<u32> = Prison::new();
prison.insert(10)?;
prison.insert(20)?;
prison.insert(30)?;
prison.insert(40)?;
prison.remove_idx(3)?;
let mut grd_0_1_2 = prison.guard_many_mut_idx(&[0, 1, 2])?;
assert!(prison.guard_many_mut_idx(&[0, 1, 2]).is_err());
assert!(prison.guard_many_mut_idx(&[5]).is_err());
assert!(prison.guard_many_mut_idx(&[3]).is_err());Sourcepub fn guard_many_ref_idx<'a>(
&'a self,
indexes: &[usize],
) -> Result<PrisonSliceRef<'a, T>, AccessError>
pub fn guard_many_ref_idx<'a>( &'a self, indexes: &[usize], ) -> Result<PrisonSliceRef<'a, T>, AccessError>
Return a PrisonSliceRef that marks all the elements as immutably referenced and wraps them in guarding data that automatically decreases their immutable reference counts when it goes out of range.
Similar to guard_many_ref() but ignores the generation counter
PrisonSliceRef
As long as the PrisonSliceRef remains in scope, the elements where it’s values reside in the Prison will remain marked as immutably referenced and unable to be mutably referenced. You can manually drop the PrisonSliceRef out of scope by passing it as the first parameter to the function [PrisonSliceRef::unguard(p_sli_ref)]
§Example
let prison: Prison<u32> = Prison::new();
prison.insert(10)?;
prison.insert(20)?;
prison.insert(30)?;
let mut grd_0_1_2 = prison.guard_many_ref_idx(&[0, 1, 2])?;
assert_eq!(*grd_0_1_2[0], 10);
prison.visit_many_ref_idx(&[0, 1, 2], |vals_0_1_2| {
assert_eq!(*vals_0_1_2[0], 10);
Ok(())
});
PrisonSliceRef::unguard(grd_0_1_2);§Errors
- [AccessError::ValueAlreadyMutablyReferenced(idx)] if any element is already mutably referenced
- [AccessError::MaximumImmutableReferencesReached(idx)] if you created usize::MAX - 2 immutable references to any element
- [AccessError::IndexOutOfRange(idx)] if any index is out of range
- [AccessError::ValueDeleted(idx, gen)] if any cell is marked as free/deleted
§Example
let prison: Prison<u32> = Prison::new();
prison.insert(10)?;
prison.insert(20)?;
prison.insert(30)?;
prison.insert(40)?;
prison.remove_idx(3)?;
let grd_0_1_2 = prison.guard_many_ref_idx(&[0, 1, 2])?;
assert!(prison.guard_many_mut_idx(&[0]).is_err());
assert!(prison.guard_many_ref_idx(&[5]).is_err());
assert!(prison.guard_many_ref_idx(&[3]).is_err());Sourcepub fn guard_slice_mut<'a, R>(
&'a self,
range: R,
) -> Result<PrisonSliceMut<'a, T>, AccessError>where
R: RangeBounds<usize>,
pub fn guard_slice_mut<'a, R>(
&'a self,
range: R,
) -> Result<PrisonSliceMut<'a, T>, AccessError>where
R: RangeBounds<usize>,
Return a PrisonSliceMut that marks all the elements as mutably referenced and wraps them in guarding data that automatically frees their mutable reference counts when it goes out of range.
Internally this is strictly identical to passing Prison::guard_many_mut_idx() a list of all indexes in the slice range, and is subject to all the same restrictions and errors
§Example
let u32_prison: Prison<u32> = Prison::new();
u32_prison.insert(42)?;
u32_prison.insert(43)?;
u32_prison.insert(44)?;
u32_prison.insert(45)?;
u32_prison.insert(46)?;
let grd_last_three = u32_prison.guard_slice_mut(2..5)?;
assert_eq!(*grd_last_three[0], 44);
assert_eq!(*grd_last_three[1], 45);
assert_eq!(*grd_last_three[2], 46);Any standard Range
§Example
let u32_prison: Prison<u32> = Prison::new();
u32_prison.insert(42)?;
u32_prison.insert(43)?;
u32_prison.insert(44)?;
u32_prison.insert(45)?;
u32_prison.insert(46)?;
assert!(u32_prison.guard_slice_mut(2..5).is_ok());
assert!(u32_prison.guard_slice_mut(2..=4).is_ok());
assert!(u32_prison.guard_slice_mut(2..).is_ok());
assert!(u32_prison.guard_slice_mut(..3).is_ok());
assert!(u32_prison.guard_slice_mut(..=3).is_ok());
assert!(u32_prison.guard_slice_mut(..).is_ok());
u32_prison.remove_idx(2)?;
assert!(u32_prison.guard_slice_mut(..).is_err());See Prison::guard_many_mut_idx() for more info
Sourcepub fn guard_slice_ref<'a, R>(
&'a self,
range: R,
) -> Result<PrisonSliceRef<'a, T>, AccessError>where
R: RangeBounds<usize>,
pub fn guard_slice_ref<'a, R>(
&'a self,
range: R,
) -> Result<PrisonSliceRef<'a, T>, AccessError>where
R: RangeBounds<usize>,
Return a PrisonSliceRef that marks all the elements as immutably referenced and wraps them in guarding data that automatically decreases their immutable reference counts when it goes out of range.
Internally this is strictly identical to passing Prison::guard_many_ref_idx() a list of all indexes in the slice range, and is subject to all the same restrictions and errors
§Example
let u32_prison: Prison<u32> = Prison::new();
u32_prison.insert(42)?;
u32_prison.insert(43)?;
u32_prison.insert(44)?;
u32_prison.insert(45)?;
u32_prison.insert(46)?;
let grd_last_three = u32_prison.guard_slice_ref(2..5)?;
let grd_all = u32_prison.guard_slice_ref(..)?;
assert_eq!(*grd_all[0], 42);
assert_eq!(*grd_all[1], 43);
assert_eq!(*grd_last_three[0], 44);
assert_eq!(*grd_last_three[1], 45);
assert_eq!(*grd_last_three[2], 46);Any standard Range
§Example
let u32_prison: Prison<u32> = Prison::new();
u32_prison.insert(42)?;
u32_prison.insert(43)?;
u32_prison.insert(44)?;
u32_prison.insert(45)?;
u32_prison.insert(46)?;
assert!(u32_prison.guard_slice_ref(2..5).is_ok());
assert!(u32_prison.guard_slice_ref(2..=4).is_ok());
assert!(u32_prison.guard_slice_ref(2..).is_ok());
assert!(u32_prison.guard_slice_ref(..3).is_ok());
assert!(u32_prison.guard_slice_ref(..=3).is_ok());
assert!(u32_prison.guard_slice_ref(..).is_ok());
u32_prison.remove_idx(2)?;
assert!(u32_prison.guard_slice_ref(..).is_err());See Prison::guard_many_ref_idx() for more info
Sourcepub fn clone_val(&self, key: CellKey) -> Result<T, AccessError>where
T: Clone,
pub fn clone_val(&self, key: CellKey) -> Result<T, AccessError>where
T: Clone,
Clones the requested value out of the Prison into a new variable
Only available when elements of type T implement Clone (it is assumed that the implementation of T::clone() is memory safe).
Because cloning does not alter the original, and because the new variable to hold the clone does not have any presumtions about the value, it is safe (in a single-threaded context) to clone out the value even if it is being visited or guarded.
This method will still return an error if the index or generation of the CellKey are invalid
§Example
let prison: Prison<String> = Prison::new();
let key_0 = prison.insert(String::from("Foo"))?;
let key_1 = prison.insert(String::from("Bar"))?;
let mut take_foo = String::new();
let mut take_bar = String::new();
prison.visit_mut(key_0, |val_0| {
take_foo = prison.clone_val(key_0)?;
Ok(())
});
let grd_1 = prison.guard_mut(key_1)?;
take_bar = prison.clone_val(key_1)?;
PrisonValueMut::unguard(grd_1);
assert_eq!(take_foo, String::from("Foo"));
assert_eq!(take_bar, String::from("Bar"));
prison.remove(key_1)?;
assert!(prison.clone_val(CellKey::from_raw_parts(10, 10)).is_err());
assert!(prison.clone_val(key_1).is_err());Sourcepub fn clone_val_idx(&self, idx: usize) -> Result<T, AccessError>where
T: Clone,
pub fn clone_val_idx(&self, idx: usize) -> Result<T, AccessError>where
T: Clone,
Clones the requested value out of the Prison into a new variable
Same as clone_val() but ignores the generation counter
Only available when elements of type T implement Clone (it is assumed that the implementation of T::clone() is memory safe).
Because cloning does not alter the original, and because the new variable to hold the clone does not have any presumtions about the value, it is safe (in a single-threaded context) to clone out the value even if it is being visited or guarded.
This method will still return an error if the index is invalid or the value is free/deleted
§Example
let prison: Prison<String> = Prison::new();
prison.insert(String::from("Foo"))?;
prison.insert(String::from("Bar"))?;
let mut take_foo = String::new();
let mut take_bar = String::new();
prison.visit_mut_idx(0, |val_0| {
take_foo = prison.clone_val_idx(0)?;
Ok(())
});
let grd_1 = prison.guard_mut_idx(1)?;
take_bar = prison.clone_val_idx(1)?;
PrisonValueMut::unguard(grd_1);
assert_eq!(take_foo, String::from("Foo"));
assert_eq!(take_bar, String::from("Bar"));
prison.remove_idx(1)?;
assert!(prison.clone_val_idx(10).is_err());
assert!(prison.clone_val_idx(1).is_err());Sourcepub fn clone_many_vals(&self, keys: &[CellKey]) -> Result<Vec<T>, AccessError>where
T: Clone,
pub fn clone_many_vals(&self, keys: &[CellKey]) -> Result<Vec<T>, AccessError>where
T: Clone,
Clones the requested values out of the Prison into a new Vec
Only available when elements of type T implement Clone (it is assumed that the implementation of T::clone() is memory safe).
Because cloning does not alter the originals, and because the new variables to hold the clones do not have any presumtions about the values, it is safe (in a single-threaded context) to clone out the values even if they are being visited or guarded.
This method will still return an error if any index or generation of the CellKeys are invalid
§Example
let prison: Prison<String> = Prison::new();
let key_0 = prison.insert(String::from("Foo"))?;
let key_1 = prison.insert(String::from("Bar"))?;
let mut take_foobar: Vec<String> = Vec::new();
prison.visit_mut(key_0, |val_0| {
let grd_1 = prison.guard_mut(key_1)?;
take_foobar = prison.clone_many_vals(&[key_0, key_1])?;
PrisonValueMut::unguard(grd_1);
Ok(())
});
assert_eq!(take_foobar[0], String::from("Foo"));
assert_eq!(take_foobar[1], String::from("Bar"));
prison.remove(key_1)?;
assert!(prison.clone_many_vals(&[CellKey::from_raw_parts(10, 10)]).is_err());
assert!(prison.clone_many_vals(&[key_1]).is_err());Sourcepub fn clone_many_vals_idx(
&self,
indexes: &[usize],
) -> Result<Vec<T>, AccessError>where
T: Clone,
pub fn clone_many_vals_idx(
&self,
indexes: &[usize],
) -> Result<Vec<T>, AccessError>where
T: Clone,
Clones the requested values out of the Prison into a new Vec
Same as clone_many_vals() but ignores the generation counter
Only available when elements of type T implement Clone (it is assumed that the implementation of T::clone() is memory safe).
Because cloning does not alter the originals, and because the new variables to hold the clones do not have any presumtions about the values, it is safe (in a single-threaded context) to clone out the values even if they are being visited or guarded.
This method will still return an error if any index is out-of-range or free/deleted
§Example
let prison: Prison<String> = Prison::new();
prison.insert(String::from("Foo"))?;
prison.insert(String::from("Bar"))?;
let mut take_foobar: Vec<String> = Vec::new();
prison.visit_mut_idx(0, |val_0| {
let grd_1 = prison.guard_mut_idx(1)?;
take_foobar = prison.clone_many_vals_idx(&[0, 1])?;
PrisonValueMut::unguard(grd_1);
Ok(())
});
assert_eq!(take_foobar[0], String::from("Foo"));
assert_eq!(take_foobar[1], String::from("Bar"));
prison.remove_idx(1)?;
assert!(prison.clone_many_vals_idx(&[10]).is_err());
assert!(prison.clone_many_vals_idx(&[1]).is_err());Sourcepub unsafe fn peek_ref<'a>(&'a self, key: CellKey) -> Result<&'a T, AccessError>
pub unsafe fn peek_ref<'a>(&'a self, key: CellKey) -> Result<&'a T, AccessError>
Get a reference to a value from it’s associated CellKey, ignoring reference counting and most other safety measures
Returns [Ok(&T)] if the value exists and the generation matches, [Err(AccessError::ValueDeleted(idx, gen))] otherwise
This method is provided as a way for libraries depending on this code to perform niche
optimized reads of contained values without the overhead of the normal safety checks,
or when a mutable reference is active but you can statically confirm that the value will
not be mutated from the begining of the returned &T’s lifetime to the end of it’s lifetime.
The returned references are intended to be short-lived and safely contained in a scope where no mutation of the Prison as a whole or ANY of its values takes place
§Safety
When you call this method and as long as the &T it returns remains in-scope/alive,
you MUST ensure the following:
- The value MUST NOT be mutated by ANY source, including active safe reference-counted mutable references
- NO operation can be performed that could potentially cause the underlying memory address of the Prison’s data to relocate
Sourcepub unsafe fn peek_ref_idx<'a>(
&'a self,
idx: usize,
) -> Result<&'a T, AccessError>
pub unsafe fn peek_ref_idx<'a>( &'a self, idx: usize, ) -> Result<&'a T, AccessError>
Get a reference to a value from it’s associated index, ignoring reference counting and most other safety measures
Returns [Ok(&T)] if the value exists, [Err(AccessError::ValueDeleted(idx, 0))] otherwise
This method is provided as a way for libraries depending on this code to perform niche
optimized reads of contained values without the overhead of the normal safety checks,
or when a mutable reference is active but you can statically confirm that the value will
not be mutated from the begining of the returned &Ts lifetime to the end of it’s lifetime.
The returned references are intended to be short-lived and safely contained in a scope where no mutation of the Prison as a whole or ANY of its values takes place
§Safety
When you call this method and as long as the &T it returns remains in-scope/alive,
you MUST ensure the following:
- The value MUST NOT be mutated by ANY source, including active safe reference-counted mutable references
- NO operation can be performed that could potentially cause the underlying memory address of the Prison’s data to relocate