[][src]Trait uninit::extension_traits::VecCapacity

pub trait VecCapacity: Sealed {
    type Item;
    fn split_at_extra_cap(&mut self) -> (&mut [Self::Item], Out<[Self::Item]>);
fn reserve_uninit(&mut self, additional: usize) -> Out<[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>]>; }
This is supported on feature="std" only.

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

Associated Types

type Item

This is supported on feature="std" only.
Loading content...

Required methods

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

This is supported on feature="std" only.

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

This is supported on feature="std" only.

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

This is supported on feature="std" only.

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

This is supported on feature="std" only.

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

This is supported on feature="std" only.

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

This is supported on feature="std" only.
Loading content...

Implementations on Foreign Types

impl<T> VecCapacity for Vec<T>[src]

type Item = T

This is supported on feature="std" only.

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

This is supported on feature="std" only.

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) {
        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]);

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

This is supported on feature="std" only.

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());
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!",
);

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

This is supported on feature="std" only.

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

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

This is supported on feature="std" only.

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

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

This is supported on feature="std" only.

Extracts an owned handle to the backing buffer.

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

This is supported on feature="std" only.

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);
Loading content...

Implementors

Loading content...