#[repr(transparent)]
pub struct UnsizedVec<T>where
    T: ?Sized,
{ /* private fields */ }
Expand description

Like Vec, but can store unsized values.

Memory layout

UnsizedVec is actually three different types rolled in to one; specialization is used to choose the optimal implementation based on the properties of T.

  1. When T is a Sized type, UnsizedVec<T> is a newtype around Vec<T>, with exactly the same memoy layout.

  2. When T is a slice, there are two heap allocations. The first is to the slices themsleves; they are laid out end-to-end, one after the other, with no padding in between. The second heap allocation is to a list of offsets, to store where each element begins and ends.

  3. When T is neither of the above, there are still two allocations. The first allocation still contains the elements of the vector laid out end-to-end, but now every element is padded to at least the alignment of the most-aligned element in the UnsizedVec. For this reason, adding a new element to the vec with a larger alignment than any of the elements already in it will add new padding to all the existing elements, which will involve a lot of copying and probably a reallocation. By default, UnsizedVec::new sets the alignment to core::mem::align_of::<usize>(), so as long as none of your trait objects are aligned to more than that, you won’t have to worry about re-padding. For this last case, the second allocation, in addition to storing offsets, also stores the pointer metadata of each element.

Managing capacity

Vec<T> has only one kind of capacity to worry about: elementwise capacity. And so does UnsizedVec<T>, as long as T: Sized. You can use functions like capacity, with_capacity and reserve to manage this capacity.

When T is a slice, there are two kinds of capacities: element capacity and byte capacity. Adding new elements to the vec is guaranteed not to reallocate as long as the number of elements doesn’t exceed the element capacity and the total size of all the elements in bytes doesn’t exceed the byte capacity. You can use functions like byte_capacity, with_capacity_bytes, and reserve_capacity_bytes to manage these two capacities.

When T is a trait object, there is a third type of capacity: alignment. To avoid reallocation when adding a new element to the vec, you need to ensure that you have sufficient element and byte capacity, and that the vec’s align is not less than the alignment of the new element. Functions like align, with_capacity_bytes_align, and reserve_capacity_bytes_align, can be used to manage all three capacities in this case.

Limitations

  • UnsizedVec<T> is invariant with respect to T; ideally, it should be covariant. This is because Rust forces invariance on all structs that contain associated types referencing T. Hopefully, future language features will allow lifting this limitation.
  • Rust functions can’t directly return unsized types. So this crate’s functions return them indirectly, though the “emplacer” mechanism defined in the emplacable crate. See that crate’s documentation for details, and the documentation of pop_into and remove_into for usage examples.

Example

#![feature(unsized_fn_params)]
use core::fmt::Debug;

use emplacable::box_new_with;
use unsized_vec::{unsize_vec, UnsizedVec};

let mut vec: UnsizedVec<dyn Debug> = unsize_vec![27.53_f32, "oh the places we'll go", Some(())];

for traitobj in &vec {
    dbg!(traitobj);
};

assert_eq!(vec.len(), 3);

let maybe_popped: Option<Box<dyn Debug>> = vec.pop_into().map(box_new_with);
let popped = maybe_popped.unwrap();
dbg!(&*popped);

assert_eq!(vec.len(), 2);

Implementations

Create a new, empty UnsizedVec. Does not allocate.

When T’s alignmnent is not known at compile-time, this uses mem::align_of::<usize>() as the default alignment.

Create a new, empty UnsizedVec with the given capacity.

When T’s alignmnent is not known at compile-time, this uses mem::align_of::<usize>() as the default alignment.

Create a new, empty UnsizedVec with the given capacity. (When T: Aligned does not hold, an alignment of 1 is used.)

When T’s alignmnent is not known at compile-time, this uses mem::align_of::<usize>() as the default alignment.

Create a new, empty UnsizedVec with the given capacity (in bytes) and alignment.

align is ignored when T’s alignment is known at compile time

Returns the number of elements the vector can hold without reallocating.

For T: ?Sized, this only concers whether metadata could get reallocated, not the elements themselves.

Returns the number of bytes the vector can hold without reallocating.

Returns the maximum alignment of the values this vector can hold without re-padding and reallocating.

Only relevant when T’s alignment is not known at compile time.

Reserves capacity for at least additional more elements to be inserted in the given UnsizedVec<T>. The collection may reserve more space to speculatively avoid frequent reallocations.

When T is not Sized, this only reseves space to store metadata. Consider using reserve_capacity_bytes instead in such cases.

Panics

Panics if the new capacity exceeds isize::MAX bytes.

Reserves capacity for at least additional more elements, taking up at least additional_bytes bytes of space, to be inserted in the given UnsizedVec<T>. The collection may reserve more space to speculatively avoid frequent reallocations.

When T’s alignment is not known at compile time, the vec may still reallocate if you push a new element onto the vec with an alignment greater than self.align(). Consider using reserve_capacity_bytes_align instead in such cases.

Panics

Panics if the either of the new capacities exceeds isize::MAX bytes.

Reserves capacity for at least additional more elements, taking up at least additional_bytes bytes of space, and with alignment of at most align, to be inserted in the given UnsizedVec<T>. The collection may reserve more space to speculatively avoid frequent reallocations.

When T’s alignment is known at compile time, align is ignored. Consider using reserve_capacity_bytes instead in such cases.

Panics

Panics if the either of the new capacities exceeds isize::MAX bytes, or if align is not a power of two.

Reserves capacity for at least additional more elements to be inserted in the given UnsizedVec<T>. Unlike reserve, this will not deliberately over-allocate to speculatively avoid frequent allocations.

When T is not Sized, this only reseves space to store metadata. Consider using reserve_exact_capacity_bytes instead in such cases.

Panics

Panics if the new capacity exceeds isize::MAX bytes.

Reserves capacity for at least additional more elements, taking up at least additional_bytes bytes of space, to be inserted in the given UnsizedVec<T>. Unlike reserve_capacity_bytes, this will not deliberately over-allocate to speculatively avoid frequent allocations.

When T’s alignment is not known at compile time, the vec may still reallocate if you push a new element onto the vec with an alignment greater than self.align(). Consider using reserve_exact_capacity_bytes_align instead in such cases.

Panics

Panics if the new capacity exceeds isize::MAX bytes.

Reserves capacity for at least additional more elements, taking up at least additional_bytes bytes of space, and with alignment of at most align, to be inserted in the given UnsizedVec<T>. Unlike reserve_capacity_bytes_align, this will not deliberately over-allocate to speculatively avoid frequent allocations.

When T’s alignment is known at compile time, align is ignored. Consider using reserve_exact_capacity_bytes instead in such cases.

Panics

Panics if the new capacity exceeds isize::MAX bytes.

Reserves capacity for at least additional more elements to be inserted in the given UnsizedVec<T>. The collection may reserve more space to speculatively avoid frequent reallocations.

When T is not Sized, this only reseves space to store metadata. Consider using try_reserve_capacity_bytes instead in such cases.

Errors

If the capacity overflows, or the allocator reports a failure, then an error is returned.

Reserves capacity for at least additional more elements, taking up at least additional_bytes bytes of space, to be inserted in the given UnsizedVec<T>. The collection may reserve more space to speculatively avoid frequent reallocations.

When T’s alignment is not known at compile time, the vec may still reallocate if you push a new element onto the vec with an alignment greater than self.align(). Consider using try_reserve_capacity_bytes_align instead in such cases.

Errors

If the capacity overflows, or the allocator reports a failure, then an error is returned.

Reserves capacity for at least additional more elements, taking up at least additional_bytes bytes of space, and with alignment of at most align, to be inserted in the given UnsizedVec<T>. The collection may reserve more space to speculatively avoid frequent reallocations.

When T’s alignment is known at compile time, align is ignored. Consider using try_reserve_capacity_bytes instead in such cases.

Errors

If the capacity overflows, or the allocator reports a failure, then an error is returned.

Panics

Panics if align is not a power of two.

Reserves capacity for at least additional more elements to be inserted in the given UnsizedVec<T>. Unlike try_reserve, this will not deliberately over-allocate to speculatively avoid frequent allocations.

When T is not Sized, this only reseves space to store metadata. Consider using try_reserve_exact_capacity_bytes instead in such cases.

Errors

If the capacity overflows, or the allocator reports a failure, then an error is returned.

Reserves capacity for at least additional more elements, taking up at least additional_bytes bytes of space, to be inserted in the given UnsizedVec<T>. Unlike try_reserve_capacity_bytes, this will not deliberately over-allocate to speculatively avoid frequent allocations.

When T’s alignment is not known at compile time, the vec may still reallocate if you push a new element onto the vec with an alignment greater than self.align(). Consider using try_reserve_exact_capacity_bytes_align instead in such cases.

Errors

If the capacity overflows, or the allocator reports a failure, then an error is returned.

Reserves capacity for at least additional more elements, taking up at least additional_bytes bytes of space, and with alignment of at most align, to be inserted in the given UnsizedVec<T>. Unlike try_reserve_capacity_bytes_align, this will not deliberately over-allocate to speculatively avoid frequent allocations.

When T’s alignment is known at compile time, align is ignored. Consider using try_reserve_exact_capacity_bytes instead in such cases.

Errors

If the capacity overflows, or the allocator reports a failure, then an error is returned.

Panics

Panics if align is not a power of two.

Shrinks all the capacities of the vec as much as possible.

Shrinks the elementwise capacity of the vector with a lower bound.

The capacity will remain at least as large as both the length and the supplied value.

If the current capacity is less than the lower limit, this is a no-op.

For T: ?Sized, this only effects elementwise capacity. Consider using shrink_capacity_bytes_to in such cases.

Shrinks the elementwise and byte capacities of the vector with lower bounds.

The capacities will remain at least as large as both the lengths and the supplied values.

If the current capacities are less than the lower limits, this is a no-op.

When T’s alignment is not known at compile-time, this only effects elementwise and bytewise capacities. Consider using shrink_capacity_bytes_align_to in such cases.

Shrinks the elementwise, byte, and alignment capacities of the vector with lower bounds.

The capacities will remain at least as large as both the lengths and the supplied values.

If the current capacities are less than the lower limits, this is a no-op.

Panics

Panics if min_align is not a power of two.

Inserts an element at position index within the vector, shifting all elements after it to the right.

If T is not Sized, you will need #![feature(unsized_fn_params)] to call this. You may also need the unsize macro, which requires additional nightly features.

Alternatively, you can use insert_unsize, which takes care of unsizing for you.

Example
#![feature(allocator_api, ptr_metadata, unsized_fn_params)]

use core::fmt::Debug;

use emplacable::unsize;
use unsized_vec::UnsizedVec;

let mut vec: UnsizedVec<dyn Debug> = UnsizedVec::new();

vec.push(unsize!([1, 2], ([i32; 2]) -> dyn Debug));
vec.insert(0, unsize!("can you believe it", (&str) -> dyn Debug));
dbg!(&vec[0]);

Appends an element to the back of a collection after unsizing it.

Examples
use core::fmt::Debug;

use unsized_vec::UnsizedVec;

let mut vec: UnsizedVec<dyn Debug> = UnsizedVec::new();

vec.push_unsize([1, 2]);
vec.insert_unsize(0, "can you believe it");
dbg!(&vec[0]);

Inserts an element at position index within the vector, shifting all elements after it to the right.

Accepts the element as an Emplacable<T, _> instead of T directly, analogously to emplacable::box_new_with.

Example
#![feature(allocator_api, ptr_metadata, unsized_fn_params)]

use core::fmt::Debug;

use unsized_vec::{unsize_vec, UnsizedVec};

let mut vec_1: UnsizedVec<dyn Debug> = unsize_vec![32, "hello"];
let mut vec_2: UnsizedVec<dyn Debug> = unsize_vec![97];

vec_2.insert_with(0, vec_1.pop_into().unwrap());

assert_eq!(vec_1.len(), 1);
assert_eq!(vec_2.len(), 2);
dbg!(&vec_2[0]);

Removes and returns the element at position index within the vector, shifting all elements after it to the left.

Because T might be unsized, and functions can’t return unsized values directly, this method returns the element using the “emplacer” mechanism. You can pass the returned Emplacable<T, _> to a function like box_new_with to get the contained T.

Example
use core::fmt::Debug;

use emplacable::box_new_with;
use unsized_vec::UnsizedVec;

let mut vec = UnsizedVec::<dyn Debug>::new();

vec.push_unsize("A beautiful day today innit");
vec.push_unsize("Quite right ol chap");

let popped: Box<dyn Debug> = box_new_with(vec.remove_into(0));
dbg!(&popped);

Appends an element to the back of a collection.

If T is not Sized, you will need #![feature(unsized_fn_params)] to call this. You may also need the unsize macro, which requires additional nightly features.

Alternatively, you can use push_unsize, which takes care of unsizing for you.

Example
#![feature(allocator_api, ptr_metadata, unsized_fn_params)]

use core::fmt::Debug;

use emplacable::unsize;
use unsized_vec::UnsizedVec;

let mut vec: UnsizedVec<dyn Debug> = UnsizedVec::new();

vec.push(unsize!([1, 2], ([i32; 2]) -> dyn Debug));
dbg!(&vec[0]);

Appends an element to the back of a collection after coercing it to an unsized type.

Example
use core::fmt::Debug;

use unsized_vec::UnsizedVec;

let mut vec: UnsizedVec<dyn Debug> = UnsizedVec::new();

vec.push_unsize([1, 2]);
dbg!(&vec[0]);

Appends an element to the back of a collection.

Accepts the element as an Emplacable<T, _> instead of T directly, analogously to emplacable::box_new_with.

#![feature(allocator_api, ptr_metadata, unsized_fn_params)]

use core::fmt::Debug;

use unsized_vec::{unsize_vec, UnsizedVec};

let mut vec_1: UnsizedVec<dyn Debug> = unsize_vec![32, "hello"];
let mut vec_2: UnsizedVec<dyn Debug> = UnsizedVec::new();

vec_2.push_with(vec_1.pop_into().unwrap());

assert_eq!(vec_1.len(), 1);
dbg!(&vec_2[0]);

Removes the last element from a vector and returns it, or None if it is empty.

Because T might be unsized, and functions can’t return unsized values directly, this method returns the element using the “emplacer” mechanism. You can pass the returned Emplacable<T, _> to a function like box_new_with to get the contained T.

Example
use core::fmt::Debug;

use emplacable::{box_new_with, Emplacable};
use unsized_vec::{UnsizedVec};

let mut vec = UnsizedVec::<dyn Debug>::new();

dbg!(vec.is_empty());
let nothing: Option<Box<dyn Debug>> = vec.pop_into().map(box_new_with);
assert!(nothing.is_none());

vec.push_unsize("A beautiful day today");
let popped: Option<Box<dyn Debug>> = vec.pop_into().map(box_new_with);
let unwrapped: Box<dyn Debug> = popped.unwrap();
dbg!(&unwrapped);

vec.push_unsize("innit?");
dbg!(&vec);

let mut popped_emplacable: Emplacable<dyn Debug, _> = vec.pop_into().unwrap();

// vec.push_unsize("yea"); // error: cannot borrow `vec` as mutable more than once at a time
// The `vec` will remain borrowed until you consume the `Emplacable`!

// or we can just drop it...
// dropping an `Emplacable` drops
// the contained value.
popped_emplacable;

assert!(vec.is_empty());

vec.push_unsize("yea"); // works now

Returns the number of elements in the vector, also referred to as its ‘length’.

Returns true if the vector contains no elements.

Returns a reference to an element, or None if index is out of range.

Returns a mutable reference to an element, or None if index is out of range.

Returns a reference to an element, without doing bounds checking.

Safety

Calling this method with an out-of-bounds index is [undefined behavior] even if the resulting reference is not used.

Returns a mutable reference to an element, without doing bounds checking.

Safety

Calling this method with an out-of-bounds index is [undefined behavior] even if the resulting reference is not used.

Returns an iterator over references to the elements of this vec.

Returns an iterator over mutable references to the elements of this vec.

Coerces this Vec’s elements to an unsized type.

Example
use core::fmt::Debug;

use unsized_vec::UnsizedVec;

let sized: Vec<u32> = vec![3, 4, 5];
let unsize: UnsizedVec<dyn Debug> = UnsizedVec::unsize(sized.into());
dbg!(&unsize);

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more
Extends a collection with the contents of an iterator. Read more
🔬This is a nightly-only experimental API. (extend_one)
Extends a collection with exactly one element.
🔬This is a nightly-only experimental API. (extend_one)
Reserves capacity in a collection for the given number of additional elements. Read more
Converts to this type from the input type.
Converts to this type from the input type.
Creates a value from an iterator. Read more
Feeds this value into the given Hasher. Read more
Feeds a slice of this type into the given Hasher. Read more
The returned type after indexing.
Performs the indexing (container[index]) operation. Read more
Performs the mutable indexing (container[index]) operation. Read more
The type of the elements being iterated over.
Which kind of iterator are we turning this into?
Creates an iterator from a value. Read more
The type of the elements being iterated over.
Which kind of iterator are we turning this into?
Creates an iterator from a value. Read more
This method returns an Ordering between self and other. Read more
Compares and returns the maximum of two values. Read more
Compares and returns the minimum of two values. Read more
Restrict a value to a certain interval. Read more
This method tests for self and other values to be equal, and is used by ==. Read more
This method tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason. Read more
This method returns an ordering between self and other values if one exists. Read more
This method tests less than (for self and other) and is used by the < operator. Read more
This method tests less than or equal to (for self and other) and is used by the <= operator. Read more
This method tests greater than (for self and other) and is used by the > operator. Read more
This method tests greater than or equal to (for self and other) and is used by the >= operator. Read more
Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.