Struct rsor::Slice

source ·
pub struct Slice<T: ?Sized> { /* private fields */ }
Expand description

Reusable slice of references.

Any method that adds references (&T or &mut T) to a Slice borrows it mutably (using &mut self) and returns a slice of references (&[&T] or &mut [&mut T], respectively). The references are only available while the returned slice is alive. After that, the Slice is logically empty again and can be reused (using references with a possibly different lifetime).

See also the crate-level documentation.

Implementations§

source§

impl<T: ?Sized> Slice<T>

source

pub fn new() -> Slice<T>

Creates a new reusable slice with capacity 0.

source

pub fn with_capacity(capacity: usize) -> Slice<T>

Creates a new reusable slice with the given capacity.

source

pub fn fill<'a, 'b, F>(&'a mut self, f: F) -> &'a [&'b T]
where F: FnOnce(Vec<&'b T>) -> Vec<&'b T>,

Returns a slice of references that has been filled by the given function.

The function f() receives an empty Vec and is supposed to fill it with the desired number of references and return the modified Vec (or an entirely different one if desired!). The references in the returned Vec are then returned in a slice of references.

The capacity of the argument passed to f() can be obtained with Slice::capacity() beforehand, or with Vec::capacity() within the function.

§Examples

Note that the lifetime 'b used to fill the Vec in f() is the same as the lifetime of the returned references. This means that even though the lifetimes between invocations are allowed to be incompatible, the lifetimes used within one invocation are still checked by the compiler with all of its dreaded rigor.

For example, the following code does not compile because the lifetime of one of the references used in f() is too short:

use rsor::Slice;

let mut reusable_slice = Slice::<str>::new();
let strings = {
    let inner_scope = String::from("inner scope is too short-lived");
    let static_str = "static &str is OK";
    reusable_slice.fill(|mut v| {
        v.push(&inner_scope);
        v.push(static_str);
        v
    })
};

This is how the compiler phrases it:

error[E0597]: `inner_scope` does not live long enough
   |
4  | let strings = {
   |     ------- borrow later stored here
...
7  |     reusable_slice.fill(|mut v| {
   |                         ------- value captured here
8  |         v.push(&inner_scope);
   |                 ^^^^^^^^^^^ borrowed value does not live long enough
...
12 | };
   | - `inner_scope` dropped here while still borrowed

For more information about this error, try `rustc --explain E0597`.

To avoid this error, we have to use a longer lifetime, for example like this:

let mut reusable_slice = Slice::<str>::new();
let same_scope = String::from("same scope is OK");
let strings = {
    let static_str = "static &str is OK";
    reusable_slice.fill(|mut v| {
        v.push(&same_scope);
        v.push(static_str);
        v
    })
};
assert_eq!(strings, ["same scope is OK", "static &str is OK"]);

Yet another contrived example, this time to show that the lifetimes 'a and 'b can be different:

use rsor::Slice;

let data = 'a';
let outer_reference = {
    let mut reusable_slice = Slice::new();
    let chars = reusable_slice.fill(|mut v| {
        v.push(&data);
        v
    });
    chars[0]
};
assert_eq!(*outer_reference, 'a');

Note that the returned value chars has the type &'a [&'b char], where 'a is the lifetime of the inner scope, while the lifetime 'b is valid until the end of the example. This is why outer_reference (with lifetime 'b) can still be accessed when reusable_slice and chars (with lifetime 'a) have already gone out of scope.

source

pub fn fill_mut<'a, 'b, F>(&'a mut self, f: F) -> &'a mut [&'b mut T]
where F: FnOnce(Vec<&'b mut T>) -> Vec<&'b mut T>,

Returns a slice of mutable references that has been filled by the given function.

Same as fill(), but for mutable references.

source

pub fn from_iter<'a, 'b, I>(&'a mut self, iter: I) -> &'a [&'b T]
where I: IntoIterator<Item = &'b T>,

Returns a slice of references that has been filled by draining an iterator.

See the crate-level documentation for examples.

source

pub fn from_iter_mut<'a, 'b, I>(&'a mut self, iter: I) -> &'a mut [&'b mut T]
where I: IntoIterator<Item = &'b mut T>,

Returns a slice of mutable references that has been filled by draining an iterator.

See the crate-level documentation for examples.

source

pub fn from_refs<'a, 'b, R>(&'a mut self, refs: &'b [R]) -> &'a [&'b T]
where R: AsRef<T> + 'b,

Returns a slice of references given a list of things that implement AsRef<T>.

§Examples

Many things implement AsRef<T>, for example Box<T>:

use rsor::Slice;

let boxes = vec![Box::new(10), Box::new(20)];
let mut reusable_slice = Slice::new();
assert_eq!(reusable_slice.from_refs(&boxes), [&10, &20]);

Strings have multiple AsRef implementations: AsRef<str> and AsRef<[u8]> (and even more!):

let strings = vec![String::from("one"), String::from("two")];
let mut reusable_slice1 = Slice::<str>::new();
let mut reusable_slice2 = Slice::<[u8]>::new();
assert_eq!(reusable_slice1.from_refs(&strings), strings);
assert_eq!(reusable_slice2.from_refs(&strings), [b"one", b"two"]);

A list of Vecs (or boxed slices etc.) can be turned into a slice of slices (&[&[T]]) by using a Slice<[T]>:

let vecs = vec![vec![1.0, 2.0, 3.0], vec![4.0, 5.0, 6.0]];
let mut reusable_slice = Slice::new();
assert_eq!(reusable_slice.from_refs(&vecs), vecs);
source

pub fn from_muts<'a, 'b, M>( &'a mut self, muts: &'b mut [M] ) -> &'a mut [&'b mut T]
where M: AsMut<T> + 'b,

Returns a mutable slice of references given a list of things that implement AsMut<T>.

This can be used like from_refs(), but this time with mutable references:

use rsor::Slice;

let mut boxes = vec![Box::new(10), Box::new(20)];
let mut reusable_slice = Slice::new();
let mut_slice = reusable_slice.from_muts(&mut boxes);
*mut_slice[1] = 30;
assert_eq!(boxes, [Box::new(10), Box::new(30)]);
let mut strings = vec![String::from("one"), String::from("two")];
let mut reusable_slice = Slice::<str>::new();
let mut_slice = reusable_slice.from_muts(&mut strings);
mut_slice[1].make_ascii_uppercase();
assert_eq!(strings, ["one", "TWO"]);
let mut vecs = vec![vec![1.0, 2.0, 3.0], vec![4.0, 5.0, 6.0]];
let mut reusable_slice = Slice::<[f32]>::new();
let mut_slice = reusable_slice.from_muts(&mut vecs);
mut_slice[1][2] += 4.0;
assert_eq!(vecs, [[1.0, 2.0, 3.0], [4.0, 5.0, 10.0]]);
source

pub fn capacity(&self) -> usize

Returns the number of references that can be used without reallocating.

Additional memory is allocated automatically when needed. To explicitly reserve a certain amount of memory, .fill() (or .fill_mut()) can be (ab)used, since it gives access to the underlying Vec:

use rsor::Slice;

let mut reusable_slice = Slice::<[f32]>::with_capacity(3);
assert_eq!(reusable_slice.capacity(), 3);
reusable_slice.fill(|mut v| {
    v.reserve_exact(7);
    v
});
assert_eq!(reusable_slice.capacity(), 7);

Trait Implementations§

source§

impl<T> Clone for Slice<T>

source§

fn clone(&self) -> Self

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<T: ?Sized> Default for Slice<T>

source§

fn default() -> Self

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

impl<T: ?Sized> Drop for Slice<T>

source§

fn drop(&mut self)

Executes the destructor for this type. Read more
source§

impl<T: ?Sized> Send for Slice<T>

A Slice can be moved between threads.

However, it cannot be moved while it’s in use (because it’s borrowed). When it’s not in use, it doesn’t contain any elements. Therefore, we don’t have to care about whether T implements Send and/or Sync.

§Examples

Despite std::rc::Rc decidedly not implementing Send, a Slice<Rc<T>> can be sent between threads:

let reusable_slice = rsor::Slice::<std::rc::Rc<i32>>::new();

std::thread::spawn(move || {
    assert_eq!(reusable_slice.capacity(), 0);
}).join().unwrap();
source§

impl<T: ?Sized> Sync for Slice<T>

A &Slice can be shared between threads.

However, a reference can only be taken when the Slice is not in use.

Auto Trait Implementations§

§

impl<T> Freeze for Slice<T>
where T: ?Sized,

§

impl<T> RefUnwindSafe for Slice<T>
where T: RefUnwindSafe + ?Sized,

§

impl<T> Unpin for Slice<T>
where T: ?Sized,

§

impl<T> UnwindSafe for Slice<T>
where T: RefUnwindSafe + ?Sized,

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> ToOwned for T
where T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

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

§

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>,

§

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.