commit 8fadf72227e60ae9d6c82fcb2cd38f11854c493c Author: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sun Oct 23 12:36:02 2022 +0200 uwu diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..4e1a577 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "haha" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..9ea908b --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "haha" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/cfg_match.rs b/src/cfg_match.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..ea0baad --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,6 @@ +#![feature(ptr_metadata)] + +mod cfg_match; +mod unsized_clone; + +pub use unsized_clone::*; diff --git a/src/unsized_clone.rs b/src/unsized_clone.rs new file mode 100644 index 0000000..2a84234 --- /dev/null +++ b/src/unsized_clone.rs @@ -0,0 +1,159 @@ +// TODO: This should probably be fallible instead of panic +// TODO: Needs more safety docs around alignment + +use std::{marker::PhantomData, ptr::Pointee}; + +/// a replacement for Clone (ignoring the old methods) +pub trait NewClone { + fn clone_unsized
(&self, place: ClonePlace
) -> InitClonePlace
;
+}
+
+/// a replacement for Copy
+pub trait NewCopy: NewClone {}
+
+/// A trait which denotes a pointer to a place
+pub trait Pointer {
+ ptr: *mut u8,
+ max_size: usize,
+ _boo: PhantomData<(P, *const T)>,
+}
+
+/// Denotes a place where something has been cloned into successfully.
+pub struct InitClonePlace {
+ ptr: *mut u8,
+ metadata: ,
+}
+
+impl ClonePlace {
+ /// Get the raw pointer of the place to write things yourself
+ pub fn as_ptr(&self) -> *const u8 {
+ self.ptr
+ }
+
+ /// Get the maximum allocation size of the place
+ pub fn max_size(&self) -> usize {
+ self.max_size
+ }
+
+ /// Create a new ClonePlace from a pointer and maximum size
+ /// # Safety
+ /// `ptr` has to be valid for writes of size `max_size`
+ unsafe fn from_raw(ptr: *mut u8, max_size: usize) -> Self {
+ Self {
+ ptr,
+ max_size,
+ _boo: PhantomData,
+ }
+ }
+
+ /// Unsafely assert that the place has been initialized for as many bytes as covered
+ /// by the metadata. This is done by using `as_ptr` and writing to it before
+ /// # Safety
+ /// `self.ptr` must be valid for reads of at least as much bytes as denoted by the `metadata`
+ unsafe fn assert_init_with_meta(
+ self,
+ metadata: {
+ InitClonePlace {
+ ptr: self.ptr,
+ metadata,
+ _boo: PhantomData,
+ }
+ }
+}
+
+impl ClonePlace {
+ /// Safe convenience function for implementing Clone via Copy
+ pub fn copy_trivially(self, data: &T) -> InitClonePlace {
+ let size = std::mem::size_of_val(data);
+ assert!(self.max_size() >= size);
+ // SAFETY: `data` is valid for reads of `sizeof(data)`
+ // `self.ptr` must be writable for at least as many bytes as `self.max_size`, which we just asserted
+ // We have initialized `self.ptr` by `sizeof(data)` bytes, meaning it's fine to assert it as init
+ unsafe {
+ std::ptr::copy_nonoverlapping(data as *const T as *const u8, self.ptr, size);
+ ClonePlace::assert_init_with_meta(self, std::ptr::metadata(data))
+ }
+ }
+}
+
+impl {
+ /// Turn the initialized place into the safe pointer type
+ pub fn into_init_value(self) -> P {
+ // SAFETY: Our pointer must point to valid initialized data
+ // The way it has been created initially asserts that it's valid for the pointer type or something like that i guess
+ unsafe { P::from_raw(std::ptr::from_raw_parts_mut(self.ptr.cast(), self.metadata)) }
+ }
+}
+
+// convenience function
+impl (&self, place: ClonePlace ) -> InitClonePlace {
+ place.copy_trivially(self)
+ }
+}
+
+impl NewCopy for str {}
+
+#[test]
+fn boxit() {
+ let str = "aaaa";
+ let place = ClonePlace::boxed(str);
+ let init_place = str.clone_unsized(place);
+ let the_box = init_place.into_init_value();
+ assert_eq!(&*the_box, "aaaa");
+}
+
+#[test]
+fn on_the_stack() {
+ let mut storage = [std::mem::MaybeUninit::