Trait UnsafeIndex

Source
pub unsafe trait UnsafeIndex<T: ?Sized>: TrustedSizedCollection {
    // Required methods
    unsafe fn get_unchecked(&self, index: usize) -> &T;
    unsafe fn get_mut_unchecked(&self, index: usize) -> &mut T;

    // Provided methods
    unsafe fn get(&self, index: usize) -> &T { ... }
    unsafe fn get_mut(&self, index: usize) -> &mut T { ... }
}
Expand description

Unsynchronized access to elements of a collection through references.

The trait allows unsynchronized access to the elements of a collection by allowing the creation of mutable references from a shared reference to the collection and its index.

The user is responsible to respect Rust’s aliasing rules (one or more shared references or exactly one mutable reference).

For more details see the individual methods.

§Safety

Implementors must be careful of undefined behavior when returning mutable references starting from a shared reference. It is advisable to learn about interior mutability before trying to implement this trait.

In particular, implementors must guarantee that references are valid and do not alias or overlap as long as different indexes are used for the trait’s methods. In addition, the following invariants must hold:

  • The collection has size len.
  • For each collection of size n, indexes are defined from 0 to n - 1, each univocally identifying an element in the collection.
  • For each index i, collection.get(i) returns a shared reference to the element identified by index i in the collection, panicking whenever i is out of bounds. It is still up to the caller to ensure Rust’s aliasing rules are respected.
  • For each index i, collection.get_unchecked(i) returns a shared reference to the element identified by index i in the collection. It is up to the caller to ensure Rust’s aliasing rules are respected and that i is in bounds.
  • For each index i, collection.get_mut(i) returns a mutable reference to the element identified by index i in the collection, panicking whenever i is out of bounds. It is still up to the caller to ensure Rust’s aliasing rules are respected.
  • For each index i, collection.get_mut_unchecked(i) returns a mutable reference to the element identified by index i in the collection. It is up to the caller to ensure Rust’s aliasing rules are respected and that i is in bounds.
  • For each valid index i, collection.get(i) == collection.get_unchecked(i).
  • For each valid index i, collection.get_mut(i) == collection.get_mut_unchecked(i).

§Examples

We can create multiple mutable references to different indexes as long as we respect Rust’s aliasing rules:

let collection = vec![0; 5].into_par_index();

unsafe {
    // This checks 0 is a valid index
    *collection.get_mut(0) = 42;
    // We know 1 is a valid index for a vector of length 5
    *collection.get_mut_unchecked(1) = 69;
}

assert_eq!(collection.into().as_ref(), vec![42, 69, 0, 0, 0]);

Note how creating two mutable references to the same index is undefined behavior:

let collection = vec![0; 5].into_par_index();

unsafe {
    let mut_ref_0 = collection.get_mut(0);
    // Instant UB: Rust's aliasing rules were violated
    let mut_ref_0_copy = collection.get_mut_unchecked(0);
}

Multiple shared references to the same index are allowed:

let collection = vec![0; 5].into_par_index();

unsafe {
    let ref_0 = collection.get(0);
    // OK: Rust's aliasing rules are not violated
    let ref_0_copy = collection.get_unchecked(0);
     
    assert_eq!(*ref_0, 0);
    assert_eq!(*ref_0_copy, 0);
}

But creating a mutable reference when any other reference to the same element exists is not:

let collection = vec![0; 5].into_par_index();

unsafe {
    let ref_0 = collection.get(0);
    // Instant UB: Rust's aliasing rules were violated
    let mut_ref_0 = collection.get_mut_unchecked(0);
}

// Equivalently

unsafe {
    let mut_ref_0 = collection.get_mut(0);
    // Instant UB: Rust's aliasing rules were violated
    let ref_0 = collection.get_unchecked(0);
}

In order to avoid this you must separate their lifetimes:

let collection = vec![0; 5].into_par_index();

unsafe {
    let ref_0 = collection.get(0);
}
unsafe {
    // OK: ref_0 no longer exists
    let mut_ref_0 = collection.get_mut_unchecked(0);
}

// Equivalently

unsafe {
    let mut_ref_0 = collection.get_mut(0);
}
unsafe {
    // OK: mut_ref_0 no longer exists
    let ref_0 = collection.get_unchecked(0);
}

Required Methods§

Source

unsafe fn get_unchecked(&self, index: usize) -> &T

Returns a shared reference to the element identified by index in the collection, without performing bounds checking.

This method does not perform bounds checking on index to ensure its validity. If you can’t guarantee its validity, you may want to use the get method instead.

§Safety

Calling this method while a mutable reference to the same element still exists is undefined behavior. Calling this method with an index i that would panic get is undefined behavior.

§Examples
let collection = vec![0; 5].into_par_index();
// We know 0 is a valid index for a collection of length 5
let ref_0: &usize = unsafe { collection.get_unchecked(0) };
assert_eq!(*ref_0, 0);
Source

unsafe fn get_mut_unchecked(&self, index: usize) -> &mut T

Returns a mutable reference to the element identified by index in the collection, without performing bounds checking.

This method does not performs bounds checking on index to ensure its validity. If you can’t guarantee its validity, you may want to use the get_mut method instead.

§Safety

Calling this method while a reference of any kind to the same element still exists is undefined behavior. Calling this method with an index i that would panic get_mut is undefined behavior.

§Examples
let collection = vec![0; 5].into_par_index();
{
    // We know 0 is a valid index for a collection of length 5
    let ref_0: &mut usize = unsafe { collection.get_mut_unchecked(0) };
    *ref_0 = 42;
}
// ref_0 is no longer in scope: we can create a shared reference to the same element
assert_eq!(unsafe { *collection.get(0) }, 42);

Provided Methods§

Source

unsafe fn get(&self, index: usize) -> &T

Returns a shared reference to the element identified by index in the collection.

This method performs bounds checking on index to ensure its validity. If you can guarantee its validity, you may want to use the get_unchecked method instead.

§Panics

Panics if index is out of bounds of the collection.

§Safety

Calling this method while a mutable reference to the same element still exists is undefined behavior.

§Examples
let collection = vec![0; 5].into_par_index();
let ref_0: &usize = unsafe { collection.get(0) };
assert_eq!(*ref_0, 0);
Source

unsafe fn get_mut(&self, index: usize) -> &mut T

Returns a mutable reference to the element identified by index in the collection.

This method performs bounds checking on index to ensure its validity. If you can guarantee its validity, you may want to use the get_mut_unchecked method instead.

§Panics

Panics if index is out of bounds of the collection.

§Safety

Calling this method while a reference of any kind to the same element still exists is undefined behavior.

§Examples
let collection = vec![0; 5].into_par_index();
{
    let ref_0: &mut usize = unsafe { collection.get_mut(0) };
    *ref_0 = 42;
}
// ref_0 is no longer in scope: we can create a shared reference to the same element
assert_eq!(unsafe { *collection.get(0) }, 42);

Implementors§