pub trait VecCapacity: Sealed {
    type Item;

    // Required methods
    fn split_at_extra_cap(
        &mut self
    ) -> (&mut [Self::Item], &mut [MaybeUninit<Self::Item>]);
    fn spare_cap(&mut self) -> &mut [MaybeUninit<Self::Item>];
    fn reserve_uninit(
        &mut self,
        additional: usize
    ) -> &mut [MaybeUninit<Self::Item>];
    fn get_backing_buffer(&mut self) -> Out<'_, [Self::Item]>
       where Self::Item: Copy;
    fn into_backing_buffer(self) -> Box<[MaybeUninit<Self::Item>]>
       where Self::Item: Copy;
    fn get_backing_buffer_with_leaking_writes(
        &mut self
    ) -> Out<'_, [Self::Item]>;
    fn into_backing_buffer_forget_elems(self) -> Box<[MaybeUninit<Self::Item>]>;
}
Available on crate features alloc or std only.
Expand description

Extension trait for Vec, allowing a non-unsafe API to interact with the backing buffer / allocation.

Required Associated Types§

Required Methods§

source

fn split_at_extra_cap( &mut self ) -> (&mut [Self::Item], &mut [MaybeUninit<Self::Item>])

source

fn spare_cap(&mut self) -> &mut [MaybeUninit<Self::Item>]

source

fn reserve_uninit( &mut self, additional: usize ) -> &mut [MaybeUninit<Self::Item>]

source

fn get_backing_buffer(&mut self) -> Out<'_, [Self::Item]>where Self::Item: Copy,

source

fn into_backing_buffer(self) -> Box<[MaybeUninit<Self::Item>]>where Self::Item: Copy,

source

fn get_backing_buffer_with_leaking_writes(&mut self) -> Out<'_, [Self::Item]>

source

fn into_backing_buffer_forget_elems(self) -> Box<[MaybeUninit<Self::Item>]>

Object Safety§

This trait is not object safe.

Implementations on Foreign Types§

source§

impl<T> VecCapacity for Vec<T>

source§

fn spare_cap(self: &mut Vec<T>) -> &mut [MaybeUninit<T>]

Same as .split_at_extra_cap().1, but for not invalidating —w.r.t. aliasing / Stacked Borrows— pointers to the initialized area of this Vec:

use ::uninit::prelude::*;

let mut v = Vec::with_capacity(2); // len = 0 && 2 uninit
v.push(0); // len = 1 && 1 uninit
let at_fst = v.as_mut_ptr();
v.spare_cap()[0] = MaybeUninit::new(27); // len = 1 && 1 init
unsafe {
    v.set_len(2); // len = 2
    *at_fst += 42; // OK, neither `spare_cap()` nor the `len` interactions invalidated this.
}
assert_eq!(v.iter().sum::<i32>(), 42 + 27);
source§

fn split_at_extra_cap(self: &mut Vec<T>) -> (&mut [T], &mut [MaybeUninit<T>])

Splits the Vec<T>’s backing buffer into two slices of initialized and uninitialized elements.

Imagine this as doing self.get_backing_buffer().split_at_out(self.len()) while upgrading the first half to &mut [T].

Guarantees (that unsafe code may rely on)

Given a vector v, and let (xs, extra) = v.split_at_extra_cap(), then:

  • xs is v.as_slice(), so:

    • xs.len() == v.len(),

    • xs.as_ptr() == v.as_ptr(),

  • extra.len() == (v.capacity() - v.len());

    • if .split_at_extra_cap() is called right after a call to .reserve(n), then v.capacity() ≥ v.len() + n, and thus extra.len() ≥ n.

      For the extra.len() == n equality to hold, one must subslice extra:

      • extra = extra.get_out(.. n).unwrap();.

      And given the aformentioned guarantees, one can even:

      • extra = extra.get_unchecked_out(.. n);

      This last idiom is covered by .reserve_uninit(n).

  • extra.as_ptr() == v.as_ptr().add(v.len()).

  • Thus, only after initializing the first k elements of extra, is it sound to v.set_len(v.len() + k);.

Example

Making a palindrome Vec:

use ::uninit::prelude::*;

fn make_palindrome<T : Copy> (v: &'_ mut Vec<T>)
{
    let len = v.len();
    v.reserve(len);
    let (xs, extra) = v.split_at_extra_cap();
    for (&x, at_dst) in xs.iter().rev().zip(extra.as_out()) {
        at_dst.write(x);
    }
    unsafe {
        // Safety: the first `len` elements of `extra` have been initialized.
        v.set_len(2 * len);
    }
}

let mut v = vec![1, 2, 3];
make_palindrome(&mut v);
assert_eq!(v, [1, 2, 3, 3, 2, 1]);
source§

fn reserve_uninit(self: &mut Vec<T>, additional: usize) -> &mut [MaybeUninit<T>]

Reserves extra (uninitialized) memory for it, returning a mutable handle to those extra (uninitialized) elements.

Example
use ::uninit::prelude::*;

let mut vec = b"Hello, ".to_vec();
const WORLD: &[u8] = b"World!";

let mut extra: Out<'_, [u8]> = vec.reserve_uninit(WORLD.len()).as_out();
extra.r().copy_from_slice(WORLD);

// `.reserve_uninit()` guarantees the following properties:
assert_eq!(extra.len(), WORLD.len());
let extra_start: *mut u8 = extra.r().as_mut_ptr().cast();
let uninit_start: *mut u8 = vec.as_mut_ptr().wrapping_add(vec.len());
assert_eq!(extra_start, uninit_start);

unsafe {
    // # Safety
    //
    //   - `.copy_from_slice()` contract guarantees initialization
    //     of `extra`, which, in turn, from `reserve_uninit`'s contract,
    //     leads to the `vec` extra capacity having been initialized.
    vec.set_len(vec.len() + WORLD.len());
}
assert_eq!(
    vec,
    b"Hello, World!",
);
source§

fn get_backing_buffer(self: &mut Vec<T>) -> Out<'_, [T]>where T: Copy,

Gets an &out [T] slice (of self.capacity() elements) to the backing buffer.

source§

fn get_backing_buffer_with_leaking_writes(self: &mut Vec<T>) -> Out<'_, [T]>

Same as .get_backing_buffer() but without the Copy bound.

This means that extra care should be taken if mem::needs_drop::<Self::Item>(). Indeed, if the OutSlice is used to overwrite initialized elements, then such elements will be destroyed without their .drop() glue / destructors ever being run.

⚠️ Misusage of this function can thus lead to memory leaks ⚠️

Counter-example
use ::uninit::prelude::*;
use ::std::rc::Rc;

let rc = Rc::new(());
assert_eq!(Rc::strong_count(&rc), 1);
let mut v = vec![ Some(Rc::clone(&rc)) ];
assert_eq!(Rc::strong_count(&rc), 2);
// This overwrites the `rc` clone  without running any destructor
// whatsoever, hence leaking it.
v   .get_backing_buffer_with_leaking_writes()
    .get_out(0)
    .unwrap()
    .write(None) // the `rc` clone is not freed
;
assert_eq!(Rc::strong_count(&rc), 2);
assert!(Rc::try_unwrap(rc).is_err());
Example
use ::uninit::prelude::*;
use ::std::cell::Cell;

let mut v = vec![Cell::new(0)];
v   .get_backing_buffer_with_leaking_writes() // No drop glue, so this is fine
    .get_out(0)
    .unwrap()
    .write(Cell::new(42))
;
assert_eq!(v[0].get(), 42);
source§

fn into_backing_buffer(self: Vec<T>) -> Box<[MaybeUninit<T>]>where T: Copy,

Extracts an owned handle to the backing buffer.

source§

fn into_backing_buffer_forget_elems(self: Vec<T>) -> Box<[MaybeUninit<T>]>

Same as .into_backing_buffer() but without the Copy bound.

This means that extra care should be taken if mem::needs_drop::<Self::Item>(). Indeed, the returned boxed slice will not run the destructor of its initialized elements (since it no longer knows which are).

⚠️ Misusage of this function can thus lead to memory leaks ⚠️

Counter-example
use ::uninit::prelude::*;
use ::std::rc::Rc;

let rc = Rc::new(());
assert_eq!(Rc::strong_count(&rc), 1);
let mut v = vec![ Some(Rc::clone(&rc)) ];
assert_eq!(Rc::strong_count(&rc), 2);
// This leaks the `rc` clone (but not the heap-allocated array containing it)
let _ = v.into_backing_buffer_forget_elems();
assert_eq!(Rc::strong_count(&rc), 2);
assert!(Rc::try_unwrap(rc).is_err());
Example
use ::uninit::prelude::*;

let mut v = vec![String::from("Hello!")];
// Good practice: before calling `.into_backing_buffer_forget_elems()`
// one ought to `.clear()` the `Vec`:
v.clear(); // drops `"Hello!"`
let mut strings_buffer: Box<[MaybeUninit<String>]> =
    v.into_backing_buffer_forget_elems()
;
strings_buffer[0] = MaybeUninit::new(String::from("Greetings!"));
let strings_buffer: Box<[String]> = unsafe {
    Box::assume_init(strings_buffer)
};
assert_eq!(&*strings_buffer[0], "Greetings!");
// This does free the contained "Greetings!" `String`.
drop(strings_buffer);
§

type Item = T

Implementors§