Skip to content

Instantly share code, notes, and snippets.

@CAD97
Created May 4, 2023 00:19
Show Gist options
  • Save CAD97/a2eb9bd977d9b08eea0b405a660d620b to your computer and use it in GitHub Desktop.
Save CAD97/a2eb9bd977d9b08eea0b405a660d620b to your computer and use it in GitHub Desktop.
TBool, ext assert, and stride experiments
#![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