Prison

Struct Prison 

Source
pub struct Prison<T> { /* private fields */ }
Expand description

The single-threaded implementation of Prison

This struct uses an underlying Vec to store data, but provides full interior mutability for each of its elements. It primarily acts like a Generational Arena using CellKey’s to index into the vector, but allows accessing elements with only a plain usize as well.

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>

Source

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)
Source

pub fn with_capacity(size: usize) -> Self

Create a new Prison with a specific starting capacity (Vec::with_capacity())

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::with_capacity(1000);
assert!(my_prison.vec_cap() == 1000)
Source

pub fn vec_len(&self) -> usize

Return the length of the underlying Vec

Because a Prison may have values that are free/deleted that are still counted within the length of the Vec, this value should not be used to determine how many valid elements exist in the Prison

Source

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

Source

pub fn num_free(&self) -> usize

Return the number of spaces available for elements to be added to the Prison without reallocating more memory.

Source

pub fn num_used(&self) -> usize

Return the number of spaces currently occupied by valid elements in the Prison

Source

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

Source

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(())
})?;
Source

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());
Source

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());
Source

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(())
})?;
Source

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(())
})?;
Source

pub fn visit_mut<F>( &self, key: CellKey, operation: F, ) -> Result<(), AccessError>
where F: FnMut(&mut T) -> 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(())
})?;
Source

pub fn visit_ref<F>( &self, key: CellKey, operation: F, ) -> Result<(), AccessError>
where F: FnMut(&T) -> 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(())
})?;
Source

pub fn visit_mut_idx<F>( &self, idx: usize, operation: F, ) -> Result<(), AccessError>
where F: FnMut(&mut T) -> 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(())
})?;
Source

pub fn visit_ref_idx<F>( &self, idx: usize, operation: F, ) -> Result<(), AccessError>
where F: FnMut(&T) -> 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(())
})?;
Source

pub fn visit_many_mut<F>( &self, keys: &[CellKey], operation: F, ) -> Result<(), AccessError>
where F: FnMut(&mut [&mut T]) -> 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());
Source

pub fn visit_many_ref<F>( &self, keys: &[CellKey], operation: F, ) -> Result<(), AccessError>
where F: FnMut(&[&T]) -> 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(())
})?;
Source

pub fn visit_many_mut_idx<F>( &self, indexes: &[usize], operation: F, ) -> Result<(), AccessError>
where F: FnMut(&mut [&mut T]) -> 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());
Source

pub fn visit_many_ref_idx<F>( &self, indexes: &[usize], operation: F, ) -> Result<(), AccessError>
where F: FnMut(&[&T]) -> 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(())
})?;
Source

pub fn visit_slice_mut<R, F>( &self, range: R, operation: F, ) -> Result<(), AccessError>
where R: RangeBounds<usize>, F: FnMut(&mut [&mut T]) -> 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 notation is allowed as the first paramater, but care must be taken because it is not guaranteed every index within range is a valid value or does not have any other references to it that would violate Rust’s memory safety.

§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

Source

pub fn visit_slice_ref<R, F>( &self, range: R, operation: F, ) -> Result<(), AccessError>
where R: RangeBounds<usize>, F: FnMut(&[&T]) -> 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 notation is allowed as the first paramater, but care must be taken because it is not guaranteed every index within range is a valid value or does not have any other references to it that would violate Rust’s memory safety.

§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

Source

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 implements [Deref<Target = T>], [DerefMut<Target = T>], AsRef, AsMut, Borrow, and BorrowMut to allow transparent access to its underlying value

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());
Source

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 implements [Deref<Target = T>], AsRef, and Borrow to allow transparent access to its underlying value

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());
Source

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 implements [Deref<Target = T>], [DerefMut<Target = T>], AsRef, AsMut, Borrow, and BorrowMut to allow transparent access to its underlying value

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());
Source

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 implements [Deref<Target = T>], AsRef, and Borrow to allow transparent access to its underlying value

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());
Source

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 implements Deref<Target = [&mut T]>, DerefMut<Target = [&mut T]>, AsRef<[&mut T]>, AsMut<[&mut T]>, Borrow<[&mut T]>, and BorrowMut<[&mut T]> to allow transparent access to its underlying slice of values

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());
Source

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 implements Deref<Target = [&T]>, AsRef<[&T]>, and Borrow<[&T]>, to allow transparent access to its underlying slice of values

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());
Source

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 implements Deref<Target = [&mut T]>, DerefMut<Target = [&mut T]>, AsRef<[&mut T]>, AsMut<[&mut T]>, Borrow<[&mut T]>, and BorrowMut<[&mut T]> to allow transparent access to its underlying slice of values

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());
Source

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 implements Deref<Target = [&T]>, AsRef<[&T]>, and Borrow<[&T]>, to allow transparent access to its underlying slice of values

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());
Source

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 notation is allowed as the first paramater, but care must be taken because it is not guaranteed every index within range is a valid value or does not have any other references to it that would violate Rust’s memory safety.

§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

Source

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 notation is allowed as the first paramater, but care must be taken because it is not guaranteed every index within range is a valid value or does not have any other references to it that would violate Rust’s memory safety.

§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

Source

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());
Source

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());
Source

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());
Source

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());
Source

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
Source

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

Trait Implementations§

Source§

impl<T: Debug> Debug for Prison<T>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<T> Default for Prison<T>

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl<T> !Freeze for Prison<T>

§

impl<T> !RefUnwindSafe for Prison<T>

§

impl<T> Send for Prison<T>
where T: Send,

§

impl<T> !Sync for Prison<T>

§

impl<T> Unpin for Prison<T>
where T: Unpin,

§

impl<T> UnwindSafe for Prison<T>
where T: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.