[][src]Trait uninit::extension_traits::BoxUninit

pub trait BoxUninit: Sealed {
    type T;
    fn uninit() -> Self;
fn init(self, value: Self::T) -> Box<Self::T>;
fn try_alloc() -> Option<Self>; }
This is supported on feature="std" only.

Extension trait for uninitalized Box allocations and the optimized delayed-initialization pattern.

Associated Types

type T

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

Required methods

fn uninit() -> Self

This is supported on feature="std" only.

fn init(self, value: Self::T) -> Box<Self::T>

This is supported on feature="std" only.

fn try_alloc() -> Option<Self>

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

Implementations on Foreign Types

impl<T> BoxUninit for Box<MaybeUninit<T>>[src]

Extension trait for uninitalized Box allocations and the optimized delayed-initialization pattern.

Optimized in-place heap initialization

The Box::uninit().init(...) delayed-initialization pattern is suprisingly effective in helping the optimizer inline the creation of the value directly into the heap.

  • In other words, this bundles ::copyless functionality.

  • For those wondering why Box::new(...) could not be made as efficient, the answer lies in temporaries: the ... temporary when calling Box::new() is created before attempting the allocation, and given that this allocation can fail / have side-effects, the optimizer is not allowed to reorder the creation of the temporary after the allocation, since it can change the semantics of the code for these corner (but not unreachable) cases. It is hence illegal for the optimizer to inline the creation of ... directly into the heap.

    Whereas Box::uninit().init(...) only creates the temporary after the allocation attempted in uninit() has succeeded, at which point it should be trivial for the optimizer to inline its creation directly into the heap.

  • Note, however, that this property cannot be guaranteed from a library perspective; for instance, the heap-inlined initialization does not seem to happen when the optimization level (opt-level) is less than 2. Inversely, the author has observed that the heap-inlined initialization does seem to kick in when compiling with -C opt-level=2 (or 3), e.g., when running on --release.

Example

use ::uninit::prelude::*;

let ft: Box<u8> = Box::uninit().init(42);
assert_eq!(*ft, 42);

This optimization can even allow creating arrays too big to fit in the stack.

  • For instance, the following implementation panics:

    fn alloc_big_boxed_array () -> Box<[u64; 10_000_000]>
    {
        // This can panic because of the `[0; 10_000_000]` stack
        // temporary overflowing the stack.
        Box::new([0; 10_000_000])
    }
  • Whereas the following one does not (doc-tested with RUSTDOCFLAGS=-Copt-level=2):

    fn alloc_big_boxed_array () -> Box<[u64; 10_000_000]>
    {
        // But this works fine, since there is no stack temporary!
        Box::uninit().init([0; 10_000_000])
    }

Handling allocation failure

A neat side-effect of this implementation is to expose the intermediate state of Box::try_alloc(), which yields an Option<Box<MaybeUninit<T>>> depending on whether the attempted allocation succeeded or not.

Example

use ::uninit::prelude::*;

let buf: Box<[u8; ::core::i32::MAX as _]> = match Box::try_alloc() {
    | Some(uninit) => uninit.init([0; ::core::i32::MAX as _]),
    | None => {
        panic!("Failed to allocate 2GB of memory");
    }
};

type T = T

This is supported on feature="std" only.

fn uninit() -> Box<MaybeUninit<T>>[src]

This is supported on feature="std" only.

Idiomatic allocation-failure unwrapping of BoxUninit::try_alloc().

fn try_alloc() -> Option<Box<MaybeUninit<T>>>[src]

This is supported on feature="std" only.

Attempts to Box-allocate memory for T, without initializing it.

Returns None when the allocation fails.

fn init(self: Box<MaybeUninit<T>>, value: T) -> Box<T>[src]

This is supported on feature="std" only.

Safely initialize a Box::MaybeUninit<T> by providing a value: T (that can be inlined into the Box), and safely return the ergonomic Box<T> witness of that initialization.

Loading content...

Implementors

Loading content...