-
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 4 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,6 +1,12 @@ | ||
//! Reimplementations of [`std::ptr::null()`] and [`std::ptr::null_mut()`], with safe code only. | ||
//! Relies on [`crate::transmute`] under the hood. | ||
|
||
use std::{ | ||
cell::Cell, | ||
marker::PhantomData, | ||
ops::{Deref, DerefMut}, | ||
}; | ||
|
||
/// Equivalent to [`std::ptr::null()`], but returns an null reference instead. | ||
pub fn null<'a, T: 'static>() -> &'a T { | ||
crate::transmute(0usize) | ||
|
@@ -15,3 +21,116 @@ pub fn null_mut<'a, T: 'static>() -> &'a mut T { | |
pub fn not_alloc<'a, T: 'static>() -> &'a mut T { | ||
null_mut() | ||
} | ||
|
||
/// 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<Cell<T>>) | ||
where | ||
T: Sized; | ||
impl<T> Clone for Ref<T> { | ||
fn clone(&self) -> Self { | ||
Self(self.0, PhantomData) | ||
} | ||
} | ||
impl<T> Ref<T> { | ||
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) | ||
} | ||
Bright-Shard marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
pub fn into_box(&self) -> Box<T> { | ||
Bright-Shard marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
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 { | ||
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 fn new<T>(o: T) -> Ref<T> | ||
where | ||
T: Sized, | ||
{ | ||
let boxx = Box::new(o); | ||
crate::transmute(boxx) | ||
} | ||
Bright-Shard marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/// Accompaning `free` function for unnewing your `new` | ||
/// | ||
/// Memory under passed reference will be freed. Upon freeing, using the same `Ref<T>` | ||
/// again or calling `free` on it is Undefined Behavior. | ||
pub fn free<T>(reff: Ref<T>) | ||
where | ||
T: Sized, | ||
{ | ||
let boxx: Box<T> = crate::transmute(reff); | ||
drop(boxx); // whoopsie | ||
} | ||
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 super::Ref; | ||
|
||
#[test] | ||
fn crossref_works() { | ||
let reff = Ref::from(3); | ||
#[allow(clippy::clone_on_copy)] | ||
let other = reff.clone(); | ||
|
||
assert_eq!(reff.addr(), other.addr()); | ||
} | ||
|
||
#[test] | ||
fn fearless_concurrency() { | ||
let reff = Ref::from(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 | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.