Created
May 4, 2023 00:19
-
-
Save CAD97/a2eb9bd977d9b08eea0b405a660d620b to your computer and use it in GitHub Desktop.
TBool, ext assert, and stride experiments
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![allow(unused)] | |
use std::marker::PhantomData; | |
use std::ops::Deref; | |
use std::mem; | |
pub trait TypeEq<T: ?Sized> {} | |
impl<T: ?Sized> TypeEq<T> for T {} | |
pub struct TBool<const B: bool>; | |
pub trait True {} | |
impl True for TBool<true> {} | |
pub trait False {} | |
impl False for TBool<false> {} | |
pub trait IBool { | |
const VALUE: bool; | |
} | |
impl<const B: bool> IBool for TBool<B> { | |
const VALUE: bool = B; | |
} | |
pub trait GBool<const B: bool> {} | |
impl<const B: bool> GBool<B> for TBool<B> {} | |
impl<const B: bool> TBool<B> { | |
pub const fn value() -> bool { B } | |
pub const fn static_assert_eq<const X: bool>() | |
where | |
Self: TypeEq<TBool<X>>, | |
{} | |
pub const fn static_assert_eq_true() | |
where | |
Self: GBool<true>, | |
{} | |
} | |
impl TBool<true> { | |
// pub const fn static_assert_eq_true() {} | |
} | |
impl TBool<false> { | |
pub const fn static_assert_eq_false() {} | |
} | |
// the usual is `fn(T) -> T`, but that forbids using ?Sized types | |
pub type PhantomInvariantTy<T> = PhantomData<for<'a> fn(&'a mut &'a mut T)>; | |
pub type PhantomInvariantLt<'a> = PhantomData<fn(&'a ()) -> &'a ()>; | |
pub trait PostMonomorphizationAssert { | |
const EVALUATE: bool; | |
} | |
macro_rules! static_assert { | |
( $cond:expr $(, $($msg:expr $(,)? )? )? ) => { | |
const _: () = { | |
::std::assert!($cond, $($($($msg)?)?)?); | |
}; | |
}; | |
} | |
macro_rules! const_assert { | |
( $cond:expr $(, $($msg:expr $(,)? )? )? ) => { | |
let _ = $crate::TBool::<{$cond}>::static_assert_eq_true(); | |
}; | |
} | |
macro_rules! PhantomInvariant { | |
[$Ty:ty] => { $crate::PhantomInvariantTy::<$Ty> }; | |
[$lt:lifetime] => { $crate::PhantomInvariantLt::<$lt> }; | |
} | |
macro_rules! mono_assert { | |
( | |
$(for[$($A:tt),* $(,)?])? | |
$(where[$($Where:tt)*])? | |
|$($X:ident: $T:ty),* $(,)?| | |
$cond:expr $(, $($msg:expr $(,)? )? )? | |
) => {{ | |
struct Assert<$($($A,)*)? $(const $X: $T,)*>( | |
$($(PhantomInvariant![$A],)*)? | |
) where $($($Where)*)?; | |
impl<$($($A,)*)? $(const $X: $T,)*> $crate::PostMonomorphizationAssert | |
for Assert<$($($A,)*)? $($X,)*> where $($($Where)*)? | |
{ | |
const EVALUATE: bool = { | |
::std::assert!($cond, $($($msg)?)?); | |
$cond | |
}; | |
} | |
if !<Assert::<$($($A,)*)? $($X,)*> as $crate::PostMonomorphizationAssert>::EVALUATE { | |
unreachable!("assertion should have cause a compile error") | |
} | |
}}; | |
} | |
unsafe trait SliceDst { | |
fn cast_from_ptr(ptr: *const [()]) -> *const Self; | |
fn as_slice_ptr(ptr: *const Self) -> *const [()]; | |
fn len(&self) -> usize { | |
sptr::slice_len(Self::as_slice_ptr(self)) | |
} | |
} | |
macro_rules! derive_SliceDst { | |
(for[$($For:tt)*] $T:ty where $($Where:tt)*) => { | |
unsafe impl<$($For)*> $crate::SliceDst for $T where $($Where)* { | |
fn cast_from_ptr(ptr: *const [()]) -> *const Self { ptr as _ } | |
fn as_slice_ptr(ptr: *const Self) -> *const [()] { ptr as _ } | |
} | |
}; | |
(launder for[$($For:tt)*] $T:ty where $($Where:tt)*) => { | |
unsafe impl<$($For)*> $crate::SliceDst for $T where $($Where)* { | |
fn cast_from_ptr(ptr: *const [()]) -> *const Self { | |
$crate::sptr::expose_addr(ptr); | |
ptr as _ | |
} | |
fn as_slice_ptr(ptr: *const Self) -> *const [()] { | |
let len = $crate::sptr::slice_len(ptr as *const [()]); | |
let ptr = $crate::sptr::launder(ptr as _); | |
$crate::sptr::slice_from_raw_parts(ptr, len) | |
} | |
} | |
}; | |
} | |
#[repr(transparent)] | |
pub struct Stride<T, const STRIDE: usize> { | |
ghost: PhantomData<[T]>, | |
slice: [()], | |
} | |
derive_SliceDst!(for[T] [T] where); | |
derive_SliceDst!(launder for[T, const S: usize] Stride<T, S> where); | |
#[repr(transparent)] | |
pub struct ConstSlice<const N: usize, T: ?Sized> { | |
ghost: PhantomData<T>, | |
} | |
impl<const N: usize, T: ?Sized + SliceDst> Deref for ConstSlice<N, T> { | |
type Target = T; | |
fn deref(&self) -> &T { | |
let ptr = sptr::slice_from_raw_parts(sptr::launder(self), N); | |
unsafe { &*SliceDst::cast_from_ptr(ptr as _) } | |
} | |
} | |
macro_rules! where_const { | |
() => {(): Sized}; | |
} | |
impl<T, const STRIDE: usize> Stride<T, STRIDE> { | |
pub fn as_ptr(&self) -> *const T { | |
sptr::launder(self.slice.as_ptr()) as _ | |
} | |
pub fn len(&self) -> usize { | |
self.slice.len() | |
} | |
pub fn get(&self, ix: usize) -> Option<&T> { | |
static_assert!(true); | |
const_assert!(false); | |
mono_assert!(for[T] |STRIDE: usize| STRIDE >= mem::size_of::<T>()); | |
mono_assert!(for[T] |STRIDE: usize| STRIDE % mem::align_of::<T>() == 0); | |
if ix >= self.len() { return None; } | |
Some(unsafe { &*sptr::byte_add(self.as_ptr(), STRIDE * ix) }) | |
} | |
} | |
pub fn stride_get(this: &Stride<u64, 8>, ix: usize) -> Option<&u64> { | |
this.get(ix) | |
} | |
mod sptr { | |
pub use std::ptr::*; | |
pub fn addr<T: ?Sized>(ptr: *const T) -> usize { | |
unsafe { std::mem::transmute(ptr as *const ()) } | |
} | |
pub fn expose_addr<T: ?Sized>(ptr: *const T) -> usize { | |
ptr as *const () as usize | |
} | |
pub fn from_addr<T>(addr: usize) -> *mut T { | |
addr as *mut T | |
} | |
pub fn launder<T>(ptr: *const T) -> *mut T { | |
from_addr(expose_addr(ptr)) | |
} | |
pub fn slice_len<T>(ptr: *const [T]) -> usize { | |
if ptr.is_null() { | |
panic!("cannot get null ptr slice len on stable"); | |
} | |
unsafe { &*(ptr as *const [()]) }.len() | |
} | |
pub unsafe fn byte_add<T>(ptr: *const T, count: usize) -> *mut T { | |
ptr.cast::<u8>().add(count).cast::<T>() as _ | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment