[−][src]Trait uninit::extension_traits::VecCapacity
feature="std"
only.Extension trait for Vec
, allowing a non-unsafe
API to interact
with the backing buffer / allocation.
Associated Types
type Item
feature="std"
only.Required methods
fn split_at_extra_cap(&mut self) -> (&mut [Self::Item], Out<[Self::Item]>)
feature="std"
only.fn reserve_uninit(&mut self, additional: usize) -> Out<[Self::Item]>
feature="std"
only.fn get_backing_buffer(&mut self) -> Out<[Self::Item]> where
Self::Item: Copy,
Self::Item: Copy,
feature="std"
only.fn into_backing_buffer(self) -> Box<[MaybeUninit<Self::Item>]> where
Self::Item: Copy,
Self::Item: Copy,
feature="std"
only.fn get_backing_buffer_with_leaking_writes(&mut self) -> Out<[Self::Item]>
feature="std"
only.fn into_backing_buffer_forget_elems(self) -> Box<[MaybeUninit<Self::Item>]>
feature="std"
only.Implementations on Foreign Types
impl<T> VecCapacity for Vec<T>
[src]
type Item = T
feature="std"
only.fn split_at_extra_cap(self: &mut Vec<T>) -> (&mut [T], Out<[T]>)
[src]
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
isv.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)
, thenv.capacity() ≥ v.len() + n
, and thusextra.len() ≥ n
.For the
extra.len() == n
equality to hold, one must subsliceextra
: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 ofextra
, is it sound tov.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]
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]
T: Copy,
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]
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]
T: Copy,
feature="std"
only.Extracts an owned handle to the backing buffer.
fn into_backing_buffer_forget_elems(self: Vec<T>) -> Box<[MaybeUninit<T>]>
[src]
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);