docs + various things

This commit is contained in:
missing 2022-05-13 10:29:14 -05:00 committed by missing
parent b633b374cb
commit 2ce9385f85
3 changed files with 104 additions and 14 deletions

View file

@ -1,3 +1,90 @@
//! # A [`Vec<T: ?Sized>`]
//!
//! A dynamic length collection of unsized elements, akin to [`std::vec::Vec`].
//!
//! This crate depends on a number of unstable features, namely:
//! - `#![feature(ptr_metadata)]`, to allow manipulating the metadata of pointers.
//! - `#![feature(layout_for_ptr)]`, to allow getting the size/alignment of a value with only a pointer to it.
//! - `#![feature(coerce_unsized)]`, to add trait bounds for types which can be unsized to another type.
//!
//! # Examples
//!
//! You can create a `Vec` with [`Vec::new`]:
//!
//! ```
//! # use std::fmt::Debug;
//! # use dyn_vec::prelude::*;
//! let vec: Vec<dyn Debug> = Vec::new();
//! # assert_eq!(format!("{:?}", vec), "[]");
//! ```
//!
//! or with the [`vec!`] macro:
//!
//! ```
//! # use dyn_vec::prelude::{*, vec};
//! # 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_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`]:
//!
//! ```
//! # use dyn_vec::prelude::{*, vec};
//! let mut vec: Vec<i32> = vec![];
//! vec.push(1);
//! vec.push(2);
//! vec.push(3);
//! # assert_eq!(format!("{:?}", vec), "[1, 2, 3]");
//! ```
//!
//! ...and with [`push_box`] and [`push_unsize`]
//!
//! ```
//! # use dyn_vec::prelude::{*, vec};
//! # use std::fmt::Debug;
//! let mut vec: Vec<dyn Debug> = vec![];
//! vec.push_box(Box::new(1));
//! vec.push_box(Box::new("foo"));
//! vec.push_box(Box::new(true));
//!
//! vec.push_unsize(2);
//! vec.push_unsize("bar");
//! vec.push_unsize(false);
//! # assert_eq!(format!("{:?}", vec), r#"[1, "foo", true, 2, "bar", false]"#);
//! ```
//!
//! # Data Layout
//!
//! ```text
//! Vec<T>
//! ┌────┬────┬────┬────┐
//! │ptr │len │cap │end │
//! └─┬──┴────┴─┬──┴─┬──┘
//! │ │ │
//! │ └────┼───────────────────────────────────────────────┐
//! ┌─┘ └───────────────────┐ │
//! │ │ │
//! ▼ ▼ ▼
//! ┌────┬────┬─────┬──────────┬───┬─────┬───────────────┬───┬───┬───┐
//! │pad │elem│pad │elem │pad│elem │ │ptr│ptr│ptr│
//! └────┴────┴─────┴──────────┴───┴─────┴───────────────┴─┬─┴─┬─┴─┬─┘
//! ▲ ▲ ▲ ▲ │ │ │ ▲
//! │ │ │ └───────────────────────┘ │ │ │
//! │ │ └──────────────────────────────────────────┘ │ │
//! │ └─────────────────────────────────────────────────────────┘ │
//! │ │
//! └─ aligned to 8 also aligned to 8 ─┘
//! ```
//!
//! [`push_box`]: Vec::push_box
//! [`push_unsize`]: Vec::push_unsize
#![feature(ptr_metadata)]
#![feature(layout_for_ptr)]
#![feature(coerce_unsized)]
@ -5,30 +92,29 @@
#[cfg(test)]
mod test;
pub mod prelude;
// Too small to put in its own file
pub mod prelude {
pub use super::{Vec, vec};
}
use core::panic;
use std::{
ptr::{NonNull, self, drop_in_place, metadata},
marker::PhantomData,
alloc::{alloc, Layout},
alloc::{alloc, Layout, dealloc},
mem::{size_of, size_of_val, align_of_val, self, size_of_val_raw},
slice,
ops::{CoerceUnsized, Index, IndexMut}
};
unsafe fn dealloc(ptr: *mut u8, layout: Layout) {
std::alloc::dealloc(ptr, layout)
}
/// Copy `size` bytes of memory from `src` to `dst`.
///
/// # Safety
///
/// `src` must be valid for reads, `dst` must be valid for writes, etc, you get the idea.
// TODO: inline me! i didnt realize it was avaliable as `copy_from` until the code was mostly complete.
// TODO: inline me! i didnt realize it was avaliable as `copy_to` until the code was mostly complete.
unsafe fn memcpy(src: *const u8, dst: *mut u8, size: usize) {
dst.copy_from(src, size);
src.copy_to(dst, size);
}
fn align_up<T: ?Sized>(ptr: *const T, align: usize) -> *const T {
@ -41,9 +127,9 @@ fn align_up_mut<T: ?Sized>(ptr: *mut T, align: usize) -> *mut T {
align_up(ptr as _, align) as _
}
/// A heap allocated, dynamically sized collection of `?Sized` elements.
/// A heap allocated, dynamic length collection of `?Sized` elements.
///
/// See [`::alloc::vec::Vec`] (the standard library `Vec` type) for more information.
/// See [`std::vec::Vec`] (the standard library `Vec` type) for more information.
pub struct Vec<T: ?Sized> {
ptr: NonNull<u8>,
len: usize,
@ -300,6 +386,12 @@ impl<T: ?Sized> Vec<T> {
mem::forget(self);
new_vec
}
unsafe fn dealloc(&self) {
if self.capacity != 0 {
dealloc(self.ptr.as_ptr(), Layout::from_size_align_unchecked(self.capacity, 8));
}
}
}
impl<T> Vec<[T]> {
@ -337,7 +429,7 @@ impl<T: ?Sized> Drop for Vec<T> {
println!("dropping {}", i);
drop_in_place(self.get_unchecked_mut(i));
}
dealloc(self.ptr.as_ptr(), Layout::from_size_align_unchecked(self.capacity, 8));
self.dealloc();
}
}
}

View file

@ -1 +0,0 @@
pub use super::{Vec, vec};

View file

@ -1,4 +1,4 @@
use super::prelude::{Vec, vec};
use super::prelude::{*, vec};
use std::{fmt::Debug, sync::atomic::{AtomicBool, Ordering}};
trait DebugExt: Debug {
@ -47,7 +47,6 @@ fn all_macro() {
Box::new(true) as _,
];
let vec3: Vec<dyn Debug> = vec![unsized: 1, String::from("foo"), true];
// assert_eq!(vec2, vec3); // doesnt compile, but would theoretically work
assert_eq!(vec2.debug(), vec3.debug());
}