-
Notifications
You must be signed in to change notification settings - Fork 117
Refs #20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Refs #20
Changes from all commits
10c9683
2a8f617
e6ef359
47e98c3
3665a5c
dacbe90
6a7f8de
9b217ba
eab5129
6bb6c02
5043864
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,14 @@ | ||
//! Reimplementations of [`std::ptr::null()`] and [`std::ptr::null_mut()`], with safe code only. | ||
//! Relies on [`crate::transmute`] under the hood. | ||
|
||
/// Equivalent to [`std::ptr::null()`], but returns a null reference instead. | ||
use std::{ | ||
marker::PhantomData, | ||
ops::{Deref, DerefMut}, | ||
rc::Rc, | ||
sync::Arc, | ||
}; | ||
|
||
/// Equivalent to [`std::ptr::null()`], but returns an null reference instead. | ||
pub fn null<'a, T: 'static>() -> &'a T { | ||
crate::transmute(0usize) | ||
} | ||
|
@@ -17,3 +24,202 @@ pub fn null_mut<'a, T: 'static>() -> &'a mut T { | |
pub fn not_alloc<'a, T: 'static>() -> &'a mut T { | ||
crate::transmute(usize::MAX) | ||
} | ||
|
||
/// Easily dereferencable raw pointer. Can be freely moved or copied. Do you really | ||
/// desire to have such power? If so, do as you wish. You've been warned. | ||
/// | ||
/// `Ref<T>` is guaranteed to be the same size as `usize` | ||
#[derive(Copy, PartialEq, Eq, PartialOrd, Ord)] | ||
#[repr(C)] | ||
pub struct Ref<T>(usize, PhantomData<Mutex<T>>) | ||
where | ||
T: Sized; | ||
impl<T> Clone for Ref<T> { | ||
fn clone(&self) -> Self { | ||
Self(self.0, PhantomData) | ||
} | ||
} | ||
impl<T> Ref<T> { | ||
pub fn new(value: T) -> Self { | ||
Self(Box::leak(Box::new(value)) as *const _ as usize, PhantomData) | ||
} | ||
|
||
pub fn free(self) { | ||
let boxx: Box<T> = crate::transmute(self); | ||
drop(boxx); | ||
} | ||
|
||
pub fn cast<U>(self) -> Ref<U> { | ||
Ref(self.0, PhantomData) | ||
} | ||
|
||
pub fn addr(&self) -> usize { | ||
self.0 | ||
} | ||
|
||
pub fn as_ptr(&self) -> *const T { | ||
crate::transmute(self.0) | ||
} | ||
|
||
pub fn as_ptr_mut(&mut self) -> *mut T { | ||
crate::transmute(self.0) | ||
} | ||
} | ||
impl<T> Ref<Ref<T>> { | ||
pub fn flatten(self) -> Ref<T> { | ||
self.deref().clone() | ||
} | ||
} | ||
impl<T> AsRef<T> for Ref<T> { | ||
fn as_ref(&self) -> &T { | ||
crate::transmute(self.0) | ||
} | ||
} | ||
impl<T> AsMut<T> for Ref<T> { | ||
fn as_mut(&mut self) -> &mut T { | ||
crate::transmute(self.0) | ||
} | ||
} | ||
impl<T> Deref for Ref<T> { | ||
type Target = T; | ||
|
||
fn deref(&self) -> &Self::Target { | ||
crate::transmute(self.0) | ||
} | ||
} | ||
impl<T> DerefMut for Ref<T> { | ||
fn deref_mut(&mut self) -> &mut Self::Target { | ||
crate::transmute(self.0) | ||
} | ||
} | ||
impl<T> From<&T> for Ref<T> { | ||
fn from(value: &T) -> Self { | ||
crate::transmute(value) | ||
} | ||
} | ||
impl<T> From<Box<T>> for Ref<T> { | ||
fn from(value: Box<T>) -> Self { | ||
let reff = crate::transmute(&*value); | ||
std::mem::forget(value); | ||
reff | ||
} | ||
} | ||
impl<T> From<Rc<T>> for Ref<T> { | ||
fn from(value: Rc<T>) -> Self { | ||
crate::transmute(&*value) | ||
} | ||
} | ||
impl<T> From<Arc<T>> for Ref<T> { | ||
fn from(value: Arc<T>) -> Self { | ||
crate::transmute(&*value) | ||
} | ||
} | ||
impl<T> From<*const T> for Ref<T> { | ||
fn from(value: *const T) -> Self { | ||
Self(value as usize, PhantomData) | ||
} | ||
} | ||
impl<T> From<*mut T> for Ref<T> { | ||
fn from(value: *mut T) -> Self { | ||
Self(value as usize, PhantomData) | ||
} | ||
} | ||
|
||
/// Brinding https://rust-lang.github.io/rfcs/0809-box-and-in-for-stdlib.html back with | ||
/// better C emulation. | ||
/// | ||
/// `Ref<T>` is guaranteed to be the size of a `usize` for all `Sized` types. For non-`Sized` | ||
/// types we have no current support anyway. | ||
pub extern "C" fn malloc<T>(value: T) -> Ref<T> | ||
where | ||
T: Sized, | ||
{ | ||
Ref::new(value) | ||
} | ||
|
||
/// Brinding https://rust-lang.github.io/rfcs/0809-box-and-in-for-stdlib.html back with | ||
/// better C emulation. | ||
/// | ||
/// `Ref<T>` is guaranteed to be the size of a `usize` for all `Sized` types. For non-`Sized` | ||
/// types we have no current support anyway. | ||
pub extern "C" fn new<T>(value: T) -> Ref<T> | ||
where | ||
T: Sized, | ||
{ | ||
Ref::new(value) | ||
} | ||
|
||
/// Accompaning `delete` function for unnewing your `new` | ||
/// | ||
/// Memory under passed reference will be freed. Upon freeing, using the same `Ref<T>` | ||
/// again or calling `delete` on it is Undefined Behavior. | ||
pub extern "C" fn delete<T>(reff: Ref<T>) | ||
where | ||
T: Sized, | ||
{ | ||
reff.free() | ||
} | ||
Bright-Shard marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/// Accompaning `free` function for unmalloccing your `malloc` | ||
/// | ||
/// Memory under passed reference will be freed. Upon freeing, using the same `Ref<T>` | ||
/// again or calling `free` on it is Undefined Behavior. | ||
pub extern "C" fn free<T>(reff: Ref<T>) | ||
where | ||
T: Sized, | ||
{ | ||
reff.free() | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can remove the module-level fns now that they're methods There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Those functions exist as to be inclusive towards the C/C++ developer community. Those can be removed, but it will make Rust less accessible for that group. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We ought to make them There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ye makes sense There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, those have names which cannot be exported There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmmm There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No such attribute There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My bad, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. cargo mommy lmfao |
||
|
||
#[cfg(test)] | ||
mod tests { | ||
use std::sync::Arc; | ||
|
||
use super::{new, Ref}; | ||
|
||
#[test] | ||
fn crossref_works() { | ||
let reff = new(3); | ||
#[allow(clippy::clone_on_copy)] | ||
let other = reff.clone(); | ||
|
||
assert_eq!(reff.addr(), other.addr()); | ||
} | ||
|
||
#[test] | ||
fn fearless_concurrency() { | ||
let reff = new(0); | ||
for _ in 0..10 { | ||
let mut reff = reff; | ||
std::thread::spawn(move || *reff += 1); | ||
} | ||
assert!(*reff <= 10); // The easiest RNG you'll even see | ||
} | ||
|
||
#[test] | ||
fn from_box() { | ||
let boxx = Box::new(3); | ||
let addr = boxx.as_ref() as *const i32 as usize; | ||
let reff: Ref<i32> = boxx.into(); | ||
|
||
assert_eq!(reff.addr(), addr); | ||
} | ||
|
||
#[test] | ||
fn arc_doesnt_break() { | ||
let mut arc1 = Arc::new(123); | ||
let arc2 = arc1.clone(); | ||
let arc2: Ref<i32> = arc2.into(); | ||
assert!(Arc::get_mut(&mut arc1).is_some()); | ||
let _ = arc2; | ||
} | ||
|
||
#[test] | ||
fn ptr_into_ref() { | ||
let val = 512; | ||
let ptr = &val as *const i32; | ||
let mut rf: Ref<i32> = ptr.into(); | ||
*rf = 69420; | ||
assert_eq!(*rf, 69420); | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.