pop, downcast, with_capacity
This commit is contained in:
parent
2ce9385f85
commit
79c5e2fef3
121
src/lib.rs
121
src/lib.rs
|
@ -9,7 +9,7 @@
|
|||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! You can create a `Vec` with [`Vec::new`]:
|
||||
//! You can create a vector with [`Vec::new`]:
|
||||
//!
|
||||
//! ```
|
||||
//! # use std::fmt::Debug;
|
||||
|
@ -25,14 +25,18 @@
|
|||
//! # use std::fmt::Debug;
|
||||
//! let vec: Vec<i32> = vec![1, 2, 3];
|
||||
//! // check the docs for `vec!` for more info on this syntax
|
||||
//! let vec_boxed: Vec<dyn Debug> = vec![box: Box::new(1) as _, Box::new("foo") as _, Box::new(true) as _];
|
||||
//! let vec_boxed: Vec<dyn Debug> = vec![box:
|
||||
//! Box::new(1) as _,
|
||||
//! Box::new("foo") as _,
|
||||
//! Box::new(true) as _
|
||||
//! ];
|
||||
//! let vec_unsized: Vec<dyn Debug> = vec![unsized: 1, "foo", true];
|
||||
//! # assert_eq!(format!("{:?}", vec), "[1, 2, 3]");
|
||||
//! # assert_eq!(format!("{:?}", vec_boxed), r#"[1, "foo", true]"#);
|
||||
//! # assert_eq!(format!("{:?}", vec_unsized), r#"[1, "foo", true]"#);
|
||||
//! ```
|
||||
//!
|
||||
//! a `Vec` can be pushed to with [`Vec::push`]:
|
||||
//! A vector can be pushed to with [`Vec::push`]:
|
||||
//!
|
||||
//! ```
|
||||
//! # use dyn_vec::prelude::{*, vec};
|
||||
|
@ -43,7 +47,7 @@
|
|||
//! # assert_eq!(format!("{:?}", vec), "[1, 2, 3]");
|
||||
//! ```
|
||||
//!
|
||||
//! ...and with [`push_box`] and [`push_unsize`]
|
||||
//! ...and with [`push_box`] and [`push_unsize`]:
|
||||
//!
|
||||
//! ```
|
||||
//! # use dyn_vec::prelude::{*, vec};
|
||||
|
@ -82,6 +86,7 @@
|
|||
//! └─ aligned to 8 also aligned to 8 ─┘
|
||||
//! ```
|
||||
//!
|
||||
//! [`Vec<T: ?Sized>`]: Vec
|
||||
//! [`push_box`]: Vec::push_box
|
||||
//! [`push_unsize`]: Vec::push_unsize
|
||||
|
||||
|
@ -89,10 +94,16 @@
|
|||
#![feature(layout_for_ptr)]
|
||||
#![feature(coerce_unsized)]
|
||||
|
||||
#![warn(missing_docs)]
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
// TODO: maybe remove this?
|
||||
// Too small to put in its own file
|
||||
/// Prelude, suitable for glob imports.
|
||||
///
|
||||
/// Using `prelude::*` will cause a conflict for the `vec!` macro. `prelude::{*, vec}` is recommended.
|
||||
pub mod prelude {
|
||||
pub use super::{Vec, vec};
|
||||
}
|
||||
|
@ -104,7 +115,8 @@ use std::{
|
|||
alloc::{alloc, Layout, dealloc},
|
||||
mem::{size_of, size_of_val, align_of_val, self, size_of_val_raw},
|
||||
slice,
|
||||
ops::{CoerceUnsized, Index, IndexMut}
|
||||
ops::{CoerceUnsized, Index, IndexMut},
|
||||
any::Any
|
||||
};
|
||||
|
||||
/// Copy `size` bytes of memory from `src` to `dst`.
|
||||
|
@ -147,7 +159,7 @@ pub use iter::*;
|
|||
type Extra<T> = *const T;
|
||||
|
||||
impl<T: ?Sized> Vec<T> {
|
||||
/// Creates a new, empty `Vec`.
|
||||
/// Creates a new, empty vector.
|
||||
pub fn new() -> Self {
|
||||
let ptr = NonNull::dangling();
|
||||
Self {
|
||||
|
@ -159,9 +171,9 @@ impl<T: ?Sized> Vec<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a new `Vec` with the given capacity (measured in bytes).
|
||||
pub fn with_capacity(cap: usize) -> Self {
|
||||
let ptr = NonNull::new(unsafe { alloc(Layout::from_size_align(cap, 8).unwrap()) }).unwrap();
|
||||
/// Creates a new vector with the given capacity, measured in bytes.
|
||||
pub fn with_capacity_bytes(cap: usize) -> Self {
|
||||
let ptr = NonNull::new(unsafe { alloc(Layout::from_size_align(cap, 8).unwrap().pad_to_align()) }).unwrap();
|
||||
Self {
|
||||
ptr,
|
||||
len: 0,
|
||||
|
@ -171,7 +183,12 @@ impl<T: ?Sized> Vec<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Appends an element to the end of the `Vec`.
|
||||
/// Creates a new vector with enough capacity to hold the given amount of `U`s.
|
||||
pub fn with_capacity_for<U>(cap: usize) -> Self {
|
||||
Self::with_capacity_bytes(cap * (size_of::<U>() + size_of::<Extra<U>>()))
|
||||
}
|
||||
|
||||
/// Appends an element to the end of the vector.
|
||||
///
|
||||
/// Only avaliable if `T: Sized`.
|
||||
pub fn push(&mut self, v: T) where T: Sized {
|
||||
|
@ -179,7 +196,7 @@ impl<T: ?Sized> Vec<T> {
|
|||
mem::forget(v);
|
||||
}
|
||||
|
||||
/// Appends an (possibly unsized) boxed element to the end of the `Vec`.
|
||||
/// Appends an (possibly unsized) boxed element to the end of the vector.
|
||||
pub fn push_box(&mut self, v: Box<T>) {
|
||||
let ptr = Box::into_raw(v);
|
||||
unsafe {
|
||||
|
@ -188,7 +205,7 @@ impl<T: ?Sized> Vec<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Appends a sized element of type `U` to the end of the `Vec`, given that it can be `CoerceUnsized` to a `T`.
|
||||
/// Appends a sized element of type `U` to the end of the vector, given that it can be `CoerceUnsized` to a `T`.
|
||||
pub fn push_unsize<U>(&mut self, v: U) where for<'a> &'a U: CoerceUnsized<&'a T> {
|
||||
let v_unsized: &T = &v;
|
||||
unsafe { self.push_raw(v_unsized) };
|
||||
|
@ -220,7 +237,7 @@ impl<T: ?Sized> Vec<T> {
|
|||
align_up_mut(self.end_ptr.as_ptr(), align_of_val(v))
|
||||
}
|
||||
|
||||
/// Checks if a given element will fill in the `Vec` without reallocations.
|
||||
/// Checks if a given element will fit in the vector without reallocations.
|
||||
pub fn will_fit(&self, v: &T) -> bool {
|
||||
let remaining_space = self.get_ptr_to_extra(self.len) as usize - self.end_ptr.as_ptr() as usize;
|
||||
let needed_space = size_of_val(v) + size_of::<Extra<T>>();
|
||||
|
@ -240,6 +257,17 @@ impl<T: ?Sized> Vec<T> {
|
|||
self.len += 1;
|
||||
}
|
||||
|
||||
/// Pops an element off the end of the vector, putting it in a [`Box`].
|
||||
pub fn pop(&mut self) -> Option<Box<T>> {
|
||||
unsafe {
|
||||
self.len = self.len.checked_sub(1)?;
|
||||
let el = self.get_ptr(self.len);
|
||||
let alloc = alloc(Layout::for_value_raw(el));
|
||||
memcpy(el.cast(), alloc, size_of_val_raw(el));
|
||||
Some(Box::from_raw(ptr::from_raw_parts_mut(alloc.cast(), metadata(el))))
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn realloc(&mut self, size: usize) {
|
||||
let layout = Layout::from_size_align_unchecked(size, 8).pad_to_align();
|
||||
if self.capacity == 0 {
|
||||
|
@ -303,6 +331,9 @@ impl<T: ?Sized> Vec<T> {
|
|||
*self.get_ptr_to_extra(index + 1)
|
||||
}
|
||||
|
||||
/// Gets a reference to the element at the specified index.
|
||||
///
|
||||
/// Returns `None` if the index is out-of-bounds.
|
||||
pub fn get(&self, index: usize) -> Option<&T> {
|
||||
if index < self.len {
|
||||
Some(unsafe { self.get_unchecked(index) })
|
||||
|
@ -311,10 +342,16 @@ impl<T: ?Sized> Vec<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Gets a reference to the element at the specified index.
|
||||
///
|
||||
/// Immediate UB if the index is out-of-bounds.
|
||||
pub unsafe fn get_unchecked(&self, index: usize) -> &T {
|
||||
&*self.get_ptr(index)
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the element at the specified index.
|
||||
///
|
||||
/// Returns `None` if the index is out-of-bounds.
|
||||
pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
|
||||
if index < self.len {
|
||||
Some(unsafe { self.get_unchecked_mut(index) })
|
||||
|
@ -323,11 +360,14 @@ impl<T: ?Sized> Vec<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the element at the specified index.
|
||||
///
|
||||
/// Immediate UB if the index is out-of-bounds.
|
||||
pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut T {
|
||||
&mut *(self.get_ptr(index) as *mut _)
|
||||
}
|
||||
|
||||
/// Returns the length of the `Vec`, which is how many items it contains.
|
||||
/// Returns the length of the vector, which is how many items it contains.
|
||||
pub fn len(&self) -> usize {
|
||||
self.len
|
||||
}
|
||||
|
@ -337,22 +377,22 @@ impl<T: ?Sized> Vec<T> {
|
|||
self.capacity
|
||||
}
|
||||
|
||||
/// Returns a pointer to the allocation of the `Vec`.
|
||||
/// Returns a pointer to the allocation of the vector.
|
||||
pub fn as_ptr(&self) -> *const u8 {
|
||||
self.ptr.as_ptr()
|
||||
}
|
||||
|
||||
/// Returns a mutable pointer to the allocation of the `Vec`.
|
||||
/// Returns a mutable pointer to the allocation of the vector.
|
||||
pub fn as_mut_ptr(&mut self) -> *mut u8 {
|
||||
self.ptr.as_ptr()
|
||||
}
|
||||
|
||||
/// Iterates over the `Vec` by-ref.
|
||||
/// Iterates over the vector by-ref.
|
||||
pub fn iter(&self) -> Iter<T> {
|
||||
Iter::new(self)
|
||||
}
|
||||
|
||||
/// Iterates over the `Vec` by-mut.
|
||||
/// Iterates over the vector by-mut.
|
||||
pub fn iter_mut(&mut self) -> IterMut<T> {
|
||||
IterMut::new(self)
|
||||
}
|
||||
|
@ -395,6 +435,9 @@ impl<T: ?Sized> Vec<T> {
|
|||
}
|
||||
|
||||
impl<T> Vec<[T]> {
|
||||
/// Returns a slice over all the elements in the vector.
|
||||
///
|
||||
/// Only avaliable for `Vec<[T]>`.
|
||||
pub fn as_slice_flatten(&self) -> &[T] {
|
||||
assert!(self.len > 0);
|
||||
|
||||
|
@ -408,6 +451,9 @@ impl<T> Vec<[T]> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns a mutable slice over all the elements in the vector.
|
||||
///
|
||||
/// Only avaliable for `Vec<[T]>`.
|
||||
pub fn as_mut_slice_flatten(&mut self) -> &mut [T] {
|
||||
assert!(self.len > 0);
|
||||
|
||||
|
@ -422,6 +468,45 @@ impl<T> Vec<[T]> {
|
|||
}
|
||||
}
|
||||
|
||||
impl Vec<dyn Any> {
|
||||
/// Gets a reference to the element at then specified index, downcasting it to the specified type.
|
||||
///
|
||||
/// Same as `.get().map(|v| v.downcast()).flatten()`.
|
||||
pub fn downcast_get<T: Any>(&self, index: usize) -> Option<&T> {
|
||||
self.get(index)?.downcast_ref()
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the element at then specified index, downcasting it to the specified type.
|
||||
///
|
||||
/// Same as `.get_mut().map(|v| v.downcast_mut()).flatten()`.
|
||||
pub fn downcast_get_mut<T: Any>(&mut self, index: usize) -> Option<&mut T> {
|
||||
self.get_mut(index)?.downcast_mut()
|
||||
}
|
||||
|
||||
/// Pops an element off the end of the vector, downcasting it to the specified type.
|
||||
///
|
||||
/// If the element is not of type `T`, the element will not be popped.
|
||||
///
|
||||
/// Similiar to `.pop().map(|v| v.downcast()).flatten()`, but without an intermediate allocation.
|
||||
pub fn downcast_pop<T: Any>(&mut self) -> Option<T> {
|
||||
unsafe {
|
||||
let el = self.get_ptr(self.len.checked_sub(1)?) as *mut dyn Any;
|
||||
let v = Some(((&mut *el).downcast_mut()? as *mut T).read());
|
||||
self.len -= 1;
|
||||
v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Vec<T> {
|
||||
/// Creates a new vector that can hold the given amount of `T`s.
|
||||
///
|
||||
/// Only avaliable when `T: Sized`.
|
||||
pub fn with_capacity(cap: usize) -> Self {
|
||||
Self::with_capacity_for::<T>(cap)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Drop for Vec<T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
|
|
41
src/test.rs
41
src/test.rs
|
@ -1,5 +1,7 @@
|
|||
//! Always use `cargo miri test`, and never just `cargo test`.
|
||||
|
||||
use super::prelude::{*, vec};
|
||||
use std::{fmt::Debug, sync::atomic::{AtomicBool, Ordering}};
|
||||
use std::{fmt::Debug, sync::atomic::{AtomicBool, Ordering}, any::Any};
|
||||
|
||||
trait DebugExt: Debug {
|
||||
fn debug(&self) -> String {
|
||||
|
@ -138,4 +140,41 @@ fn zst() {
|
|||
drop(el);
|
||||
}
|
||||
assert_eq!(vec.debug(), "[(), (), ()]");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn downcast() {
|
||||
let mut vec: Vec<dyn Any> = vec![unsized: 1, String::from("foo"), true];
|
||||
|
||||
assert_eq!(vec.downcast_get::<f32>(0), None);
|
||||
assert_eq!(vec.downcast_get::<i32>(0), Some(&1));
|
||||
assert_eq!(vec.downcast_get_mut::<f32>(1), None);
|
||||
assert_eq!(vec.downcast_get_mut::<String>(1), Some(&mut String::from("foo")));
|
||||
assert_eq!(vec.downcast_pop::<f32>(), None);
|
||||
assert_eq!(vec.downcast_pop::<bool>(), Some(true));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pop() {
|
||||
let mut vec: Vec<dyn Debug> = vec![unsized: 1, String::from("foo"), true];
|
||||
|
||||
assert_eq!(vec.pop().debug(), "Some(true)");
|
||||
assert_eq!(vec.pop().debug(), "Some(\"foo\")");
|
||||
assert_eq!(vec.pop().debug(), "Some(1)");
|
||||
assert_eq!(vec.pop().debug(), "None");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn with_capacity() {
|
||||
// 4 and not 3 cause of `Layout::pad_to_align`
|
||||
let mut vec = Vec::with_capacity(4);
|
||||
|
||||
let prev_ptr = vec.as_ptr();
|
||||
|
||||
vec.push(1);
|
||||
vec.push(2);
|
||||
vec.push(3);
|
||||
vec.push(4);
|
||||
|
||||
assert_eq!(prev_ptr, vec.as_ptr());
|
||||
}
|
Loading…
Reference in a new issue