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
|
//! # Examples
|
||||||
//!
|
//!
|
||||||
//! You can create a `Vec` with [`Vec::new`]:
|
//! You can create a vector with [`Vec::new`]:
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! # use std::fmt::Debug;
|
//! # use std::fmt::Debug;
|
||||||
|
@ -25,14 +25,18 @@
|
||||||
//! # use std::fmt::Debug;
|
//! # use std::fmt::Debug;
|
||||||
//! let vec: Vec<i32> = vec![1, 2, 3];
|
//! let vec: Vec<i32> = vec![1, 2, 3];
|
||||||
//! // check the docs for `vec!` for more info on this syntax
|
//! // 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];
|
//! let vec_unsized: Vec<dyn Debug> = vec![unsized: 1, "foo", true];
|
||||||
//! # assert_eq!(format!("{:?}", vec), "[1, 2, 3]");
|
//! # assert_eq!(format!("{:?}", vec), "[1, 2, 3]");
|
||||||
//! # assert_eq!(format!("{:?}", vec_boxed), r#"[1, "foo", true]"#);
|
//! # assert_eq!(format!("{:?}", vec_boxed), r#"[1, "foo", true]"#);
|
||||||
//! # assert_eq!(format!("{:?}", vec_unsized), 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};
|
//! # use dyn_vec::prelude::{*, vec};
|
||||||
|
@ -43,7 +47,7 @@
|
||||||
//! # assert_eq!(format!("{:?}", vec), "[1, 2, 3]");
|
//! # 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};
|
//! # use dyn_vec::prelude::{*, vec};
|
||||||
|
@ -82,6 +86,7 @@
|
||||||
//! └─ aligned to 8 also aligned to 8 ─┘
|
//! └─ aligned to 8 also aligned to 8 ─┘
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
//! [`Vec<T: ?Sized>`]: Vec
|
||||||
//! [`push_box`]: Vec::push_box
|
//! [`push_box`]: Vec::push_box
|
||||||
//! [`push_unsize`]: Vec::push_unsize
|
//! [`push_unsize`]: Vec::push_unsize
|
||||||
|
|
||||||
|
@ -89,10 +94,16 @@
|
||||||
#![feature(layout_for_ptr)]
|
#![feature(layout_for_ptr)]
|
||||||
#![feature(coerce_unsized)]
|
#![feature(coerce_unsized)]
|
||||||
|
|
||||||
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test;
|
mod test;
|
||||||
|
|
||||||
|
// TODO: maybe remove this?
|
||||||
// Too small to put in its own file
|
// 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 mod prelude {
|
||||||
pub use super::{Vec, vec};
|
pub use super::{Vec, vec};
|
||||||
}
|
}
|
||||||
|
@ -104,7 +115,8 @@ use std::{
|
||||||
alloc::{alloc, Layout, dealloc},
|
alloc::{alloc, Layout, dealloc},
|
||||||
mem::{size_of, size_of_val, align_of_val, self, size_of_val_raw},
|
mem::{size_of, size_of_val, align_of_val, self, size_of_val_raw},
|
||||||
slice,
|
slice,
|
||||||
ops::{CoerceUnsized, Index, IndexMut}
|
ops::{CoerceUnsized, Index, IndexMut},
|
||||||
|
any::Any
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Copy `size` bytes of memory from `src` to `dst`.
|
/// Copy `size` bytes of memory from `src` to `dst`.
|
||||||
|
@ -147,7 +159,7 @@ pub use iter::*;
|
||||||
type Extra<T> = *const T;
|
type Extra<T> = *const T;
|
||||||
|
|
||||||
impl<T: ?Sized> Vec<T> {
|
impl<T: ?Sized> Vec<T> {
|
||||||
/// Creates a new, empty `Vec`.
|
/// Creates a new, empty vector.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let ptr = NonNull::dangling();
|
let ptr = NonNull::dangling();
|
||||||
Self {
|
Self {
|
||||||
|
@ -159,9 +171,9 @@ impl<T: ?Sized> Vec<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new `Vec` with the given capacity (measured in bytes).
|
/// Creates a new vector with the given capacity, measured in bytes.
|
||||||
pub fn with_capacity(cap: usize) -> Self {
|
pub fn with_capacity_bytes(cap: usize) -> Self {
|
||||||
let ptr = NonNull::new(unsafe { alloc(Layout::from_size_align(cap, 8).unwrap()) }).unwrap();
|
let ptr = NonNull::new(unsafe { alloc(Layout::from_size_align(cap, 8).unwrap().pad_to_align()) }).unwrap();
|
||||||
Self {
|
Self {
|
||||||
ptr,
|
ptr,
|
||||||
len: 0,
|
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`.
|
/// Only avaliable if `T: Sized`.
|
||||||
pub fn push(&mut self, v: T) where T: Sized {
|
pub fn push(&mut self, v: T) where T: Sized {
|
||||||
|
@ -179,7 +196,7 @@ impl<T: ?Sized> Vec<T> {
|
||||||
mem::forget(v);
|
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>) {
|
pub fn push_box(&mut self, v: Box<T>) {
|
||||||
let ptr = Box::into_raw(v);
|
let ptr = Box::into_raw(v);
|
||||||
unsafe {
|
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> {
|
pub fn push_unsize<U>(&mut self, v: U) where for<'a> &'a U: CoerceUnsized<&'a T> {
|
||||||
let v_unsized: &T = &v;
|
let v_unsized: &T = &v;
|
||||||
unsafe { self.push_raw(v_unsized) };
|
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))
|
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 {
|
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 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>>();
|
let needed_space = size_of_val(v) + size_of::<Extra<T>>();
|
||||||
|
@ -240,6 +257,17 @@ impl<T: ?Sized> Vec<T> {
|
||||||
self.len += 1;
|
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) {
|
unsafe fn realloc(&mut self, size: usize) {
|
||||||
let layout = Layout::from_size_align_unchecked(size, 8).pad_to_align();
|
let layout = Layout::from_size_align_unchecked(size, 8).pad_to_align();
|
||||||
if self.capacity == 0 {
|
if self.capacity == 0 {
|
||||||
|
@ -303,6 +331,9 @@ impl<T: ?Sized> Vec<T> {
|
||||||
*self.get_ptr_to_extra(index + 1)
|
*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> {
|
pub fn get(&self, index: usize) -> Option<&T> {
|
||||||
if index < self.len {
|
if index < self.len {
|
||||||
Some(unsafe { self.get_unchecked(index) })
|
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 {
|
pub unsafe fn get_unchecked(&self, index: usize) -> &T {
|
||||||
&*self.get_ptr(index)
|
&*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> {
|
pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
|
||||||
if index < self.len {
|
if index < self.len {
|
||||||
Some(unsafe { self.get_unchecked_mut(index) })
|
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 {
|
pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut T {
|
||||||
&mut *(self.get_ptr(index) as *mut _)
|
&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 {
|
pub fn len(&self) -> usize {
|
||||||
self.len
|
self.len
|
||||||
}
|
}
|
||||||
|
@ -337,22 +377,22 @@ impl<T: ?Sized> Vec<T> {
|
||||||
self.capacity
|
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 {
|
pub fn as_ptr(&self) -> *const u8 {
|
||||||
self.ptr.as_ptr()
|
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 {
|
pub fn as_mut_ptr(&mut self) -> *mut u8 {
|
||||||
self.ptr.as_ptr()
|
self.ptr.as_ptr()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterates over the `Vec` by-ref.
|
/// Iterates over the vector by-ref.
|
||||||
pub fn iter(&self) -> Iter<T> {
|
pub fn iter(&self) -> Iter<T> {
|
||||||
Iter::new(self)
|
Iter::new(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterates over the `Vec` by-mut.
|
/// Iterates over the vector by-mut.
|
||||||
pub fn iter_mut(&mut self) -> IterMut<T> {
|
pub fn iter_mut(&mut self) -> IterMut<T> {
|
||||||
IterMut::new(self)
|
IterMut::new(self)
|
||||||
}
|
}
|
||||||
|
@ -395,6 +435,9 @@ impl<T: ?Sized> Vec<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> 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] {
|
pub fn as_slice_flatten(&self) -> &[T] {
|
||||||
assert!(self.len > 0);
|
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] {
|
pub fn as_mut_slice_flatten(&mut self) -> &mut [T] {
|
||||||
assert!(self.len > 0);
|
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> {
|
impl<T: ?Sized> Drop for Vec<T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
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 super::prelude::{*, vec};
|
||||||
use std::{fmt::Debug, sync::atomic::{AtomicBool, Ordering}};
|
use std::{fmt::Debug, sync::atomic::{AtomicBool, Ordering}, any::Any};
|
||||||
|
|
||||||
trait DebugExt: Debug {
|
trait DebugExt: Debug {
|
||||||
fn debug(&self) -> String {
|
fn debug(&self) -> String {
|
||||||
|
@ -138,4 +140,41 @@ fn zst() {
|
||||||
drop(el);
|
drop(el);
|
||||||
}
|
}
|
||||||
assert_eq!(vec.debug(), "[(), (), ()]");
|
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