mirror of
https://github.com/Noratrieb/the-good-stuff.git
synced 2026-01-14 16:45:01 +01:00
uwu
This commit is contained in:
commit
8fadf72227
6 changed files with 181 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
/target
|
||||||
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
|
|
@ -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"
|
||||||
8
Cargo.toml
Normal file
8
Cargo.toml
Normal file
|
|
@ -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]
|
||||||
0
src/cfg_match.rs
Normal file
0
src/cfg_match.rs
Normal file
6
src/lib.rs
Normal file
6
src/lib.rs
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
#![feature(ptr_metadata)]
|
||||||
|
|
||||||
|
mod cfg_match;
|
||||||
|
mod unsized_clone;
|
||||||
|
|
||||||
|
pub use unsized_clone::*;
|
||||||
159
src/unsized_clone.rs
Normal file
159
src/unsized_clone.rs
Normal file
|
|
@ -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<P>(&self, place: ClonePlace<P, Self>) -> InitClonePlace<P, Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// a replacement for Copy
|
||||||
|
pub trait NewCopy: NewClone {}
|
||||||
|
|
||||||
|
/// A trait which denotes a pointer to a place
|
||||||
|
pub trait Pointer<T: ?Sized> {
|
||||||
|
/// Create a pointer from a raw pointer
|
||||||
|
/// # Safety
|
||||||
|
/// The pointer needs to be valid to create a `Self`. This method can't really be called
|
||||||
|
/// generically, but `ClonePlace` provides a safe interface over it.
|
||||||
|
unsafe fn from_raw(ptr: *mut T) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized> Pointer<T> for Box<T> {
|
||||||
|
unsafe fn from_raw(ptr: *mut T) -> Self {
|
||||||
|
Self::from_raw(ptr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized> Pointer<T> for &mut T {
|
||||||
|
unsafe fn from_raw(ptr: *mut T) -> Self {
|
||||||
|
&mut *ptr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// more impls...
|
||||||
|
|
||||||
|
/// Denotes a place which something can be cloned into.
|
||||||
|
pub struct ClonePlace<P, T: ?Sized> {
|
||||||
|
ptr: *mut u8,
|
||||||
|
max_size: usize,
|
||||||
|
_boo: PhantomData<(P, *const T)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Denotes a place where something has been cloned into successfully.
|
||||||
|
pub struct InitClonePlace<P, T: ?Sized> {
|
||||||
|
ptr: *mut u8,
|
||||||
|
metadata: <T as Pointee>::Metadata,
|
||||||
|
_boo: PhantomData<P>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P, T: ?Sized> ClonePlace<P, T> {
|
||||||
|
/// 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: <T as Pointee>::Metadata,
|
||||||
|
) -> InitClonePlace<P, T> {
|
||||||
|
InitClonePlace {
|
||||||
|
ptr: self.ptr,
|
||||||
|
metadata,
|
||||||
|
_boo: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P, T: ?Sized + NewCopy> ClonePlace<P, T> {
|
||||||
|
/// Safe convenience function for implementing Clone via Copy
|
||||||
|
pub fn copy_trivially(self, data: &T) -> InitClonePlace<P, T> {
|
||||||
|
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<P: Pointer<T>, T: ?Sized> InitClonePlace<P, T> {
|
||||||
|
/// 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<T: ?Sized> ClonePlace<Box<T>, T> {
|
||||||
|
/// Creates a new boxed ClonePlace and allocates as many bytes as required for `value`
|
||||||
|
pub fn boxed(value: &T) -> Self {
|
||||||
|
// SAFETY: We checked the pointer for null meaning it's valid for `laoyut.size()` bytes
|
||||||
|
// That's the safety requirement for creating a box basically so we're fine
|
||||||
|
unsafe {
|
||||||
|
let layout = std::alloc::Layout::for_value(value);
|
||||||
|
let allocated = std::alloc::alloc(layout);
|
||||||
|
if allocated.is_null() {
|
||||||
|
std::alloc::handle_alloc_error(layout);
|
||||||
|
}
|
||||||
|
Self::from_raw(allocated, layout.size())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NewClone for str {
|
||||||
|
fn clone_unsized<P>(&self, place: ClonePlace<P, Self>) -> InitClonePlace<P, Self> {
|
||||||
|
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::<u8>::uninit(); 10];
|
||||||
|
let str = "aaaa";
|
||||||
|
|
||||||
|
// SAFETY: `storage` is valid for writes of 10 bytes.
|
||||||
|
let place: ClonePlace<&mut str, _> =
|
||||||
|
unsafe { ClonePlace::from_raw(storage.as_mut_ptr().cast::<u8>(), 10) };
|
||||||
|
|
||||||
|
let init_place = str.clone_unsized(place);
|
||||||
|
let the_box = init_place.into_init_value();
|
||||||
|
assert_eq!(&*the_box, "aaaa");
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue