Skip to content

Instantly share code, notes, and snippets.

@ProgramCrafter
Created September 16, 2024 16:23
Show Gist options
  • Save ProgramCrafter/c79293307b7df0740b87ae244072a4d3 to your computer and use it in GitHub Desktop.
Save ProgramCrafter/c79293307b7df0740b87ae244072a4d3 to your computer and use it in GitHub Desktop.
#![allow(incomplete_features)]
#![feature(generic_const_exprs)]
#![feature(maybe_uninit_write_slice, maybe_uninit_array_assume_init)]
use std::{fmt::{Display, Formatter}, mem::MaybeUninit};
use is_true::IsTrue;
use size_def::{Bound, CtSize, Erased, Fixed};
mod is_true {
pub trait IsTrue<const COND: bool> {}
impl IsTrue<true> for () {}
}
trait ToVec<T: Clone>: Clone {
fn copy_to_vec(self) -> Vec<T>;
fn len(&self) -> usize;
}
impl<T: Clone> ToVec<T> for Vec<T> {
fn copy_to_vec(self) -> Vec<T> {self}
fn len(&self) -> usize {self.len()}
}
impl<const B: usize, T: Clone> ToVec<T> for [T; B] {
fn copy_to_vec(self) -> Vec<T> {self.to_vec()}
fn len(&self) -> usize {B}
}
mod size_def {
use std::fmt::Debug;
use crate::{is_true::IsTrue, ToVec};
trait Sealed : Debug + Copy {}
#[allow(private_bounds)]
pub trait CtSize : Sealed {
type Storage<T: Clone>: ToVec<T>;
fn lower_bound() -> usize;
fn upper_bound() -> usize;
}
#[derive(Debug, Clone, Copy)]
pub struct Fixed<const BITS: usize>;
impl<const BITS: usize> Sealed for Fixed<BITS> where (): IsTrue<{BITS <= 1023}> {}
impl<const BITS: usize> CtSize for Fixed<BITS> where (): IsTrue<{BITS <= 1023}> {
type Storage<T: Clone> = [T; BITS];
fn lower_bound() -> usize {BITS}
fn upper_bound() -> usize {BITS + 1}
}
#[derive(Debug, Clone, Copy)]
pub struct Bound<const LB: usize, const UB: usize>;
impl<const LB: usize, const UB: usize> Sealed for Bound<LB, UB>
where (): IsTrue<{LB < UB}>, (): IsTrue<{UB <= 1024}> {}
impl<const LB: usize, const UB: usize> CtSize for Bound<LB, UB>
where (): IsTrue<{LB < UB}>, (): IsTrue<{UB <= 1024}> {
type Storage<T: Clone> = Vec<T>;
fn lower_bound() -> usize {LB}
fn upper_bound() -> usize {UB}
}
#[derive(Debug, Clone, Copy)]
pub struct Erased;
impl Sealed for Erased {}
impl CtSize for Erased {
type Storage<T: Clone> = Vec<T>;
fn lower_bound() -> usize {0}
fn upper_bound() -> usize {isize::MAX as usize + 1}
}
}
#[derive(Debug, Clone)]
struct Builder<BITS: CtSize, REFS: CtSize> {
bits: BITS::Storage<bool>,
refs: REFS::Storage<()>,
}
impl<BITS: CtSize, REFS: CtSize> Display for Builder<BITS, REFS> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
let this = self.clone().erase_len();
write!(f, "{}[", this.bits.len())?;
for hex in this.bits.chunks(4) {
let mut a = 0_u8;
for bit in hex {a = a * 2 + if *bit {1} else {0};}
if hex.len() < 4 {a = (a * 2 + 1) << (3 - hex.len());}
write!(f, "{a:X}")?;
}
if this.bits.len() % 4 != 0 {
write!(f, "_")?;
}
write!(f, "]{:?}", this.refs)?;
Ok(())
}
}
type FBuilder<const B: usize, const R: usize> = Builder<Fixed<B>, Fixed<R>>;
type ErBuilder = Builder<Erased, Erased>;
impl FBuilder<0, 0> {
fn new() -> Self {
Self {bits: [], refs: []}
}
}
impl<BITS: CtSize, REFS: CtSize> Builder<BITS, REFS> {
fn erase_bits_len(self) -> Builder<Erased, REFS> {
Builder {bits: self.bits.copy_to_vec(), refs: self.refs}
}
fn erase_refs_len(self) -> Builder<BITS, Erased> {
Builder {bits: self.bits, refs: self.refs.copy_to_vec()}
}
fn erase_len(self) -> ErBuilder {
Builder {bits: self.bits.copy_to_vec(), refs: self.refs.copy_to_vec()}
}
}
impl<const B: usize, REFS: CtSize> Builder<Fixed<B>, REFS>
where (): IsTrue<{B <= 1023}>,
(): IsTrue<{B+1 <= 1024}>, (): IsTrue<{B < B+1}> { // only for inference
fn relax_bit_len(self) -> Builder<Bound<B, {B + 1}>, REFS> {
let result = Builder {bits: self.bits.copy_to_vec(), refs: self.refs};
let b: &Vec<bool> = &result.bits;
debug_assert!(b.len() >= B && b.len() < B + 1);
result
}
}
impl<const R: usize, BITS: CtSize> Builder<BITS, Fixed<R>>
where (): IsTrue<{R <= 1023}>,
(): IsTrue<{R+1 <= 1024}>, (): IsTrue<{R < R+1}> { // only for inference
fn relax_ref_len(self) -> Builder<BITS, Bound<R, {R + 1}>> {
let result = Builder {bits: self.bits, refs: self.refs.copy_to_vec()};
let r: &Vec<()> = &result.refs;
debug_assert!(r.len() >= R && r.len() < R + 1);
result
}
}
macro_rules! uint_to_builder {
($($cur_type:ty)+) => {
$(
/*
trait NeededType {}
impl NeededType for $cur_type {}
*/
impl From<$cur_type> for FBuilder<{<$cur_type>::BITS as usize}, 0> {
fn from(value: $cur_type) -> Self {
Self {bits: core::array::from_fn(|i| (value >> i) & 1 == 1),
refs: []}
}
}
)+
};
}
uint_to_builder!(u8 u16 u32 u64 u128);
#[derive(Debug)]
enum BuilderOverflows {Bit, Ref}
trait Concatable<Rhs> {
type Res;
fn concat(self, rhs: Rhs) -> Self::Res;
}
impl<const B1: usize, const R1: usize, const B2: usize, const R2: usize>
Concatable<FBuilder<B2, R2>> for FBuilder<B1, R1>
where (): IsTrue<{B1 <= 1023}>, (): IsTrue<{B2 <= 1023}>, (): IsTrue<{B1+B2 <= 1023}>,
(): IsTrue<{R1 <= 1023}>, (): IsTrue<{R2 <= 1023}>, (): IsTrue<{R1+R2 <= 1023}> {
type Res = FBuilder<{B1+B2}, {R1+R2}>;
fn concat(self, rhs: FBuilder<B2, R2>) -> Self::Res {
let mut bits = [MaybeUninit::<bool>::uninit(); B1 + B2];
let mut refs = [MaybeUninit::<()>::uninit(); R1 + R2];
MaybeUninit::copy_from_slice(&mut bits[0..B1], &self.bits);
MaybeUninit::copy_from_slice(&mut bits[B1..], &rhs.bits);
MaybeUninit::copy_from_slice(&mut refs[0..R1], &self.refs);
MaybeUninit::copy_from_slice(&mut refs[R1..], &rhs.refs);
// SAFETY: array sizes were checked by compiler so everything is initialized now
// or MIRI may raise an exception
Builder {bits: unsafe {MaybeUninit::array_assume_init(bits)},
refs: unsafe {MaybeUninit::array_assume_init(refs)}}
}
}
impl<BITS: CtSize, REFS: CtSize> Concatable<Builder<BITS, REFS>> for ErBuilder {
type Res = Result<ErBuilder, (ErBuilder, ErBuilder, BuilderOverflows)>;
fn concat(mut self, rhs: Builder<BITS, REFS>) -> Self::Res {
let mut rhs = rhs.erase_len();
if self.bits.len() + rhs.bits.len() > 1023 {
return Err((self, rhs, BuilderOverflows::Bit))
}
if self.refs.len() + rhs.refs.len() > 3 {
return Err((self, rhs, BuilderOverflows::Ref))
}
self.bits.append(&mut rhs.bits);
self.refs.append(&mut rhs.refs);
Ok(self)
}
}
fn main() {
let b = Builder::new()
.concat((1600_u64).into())
.concat((1700_u128).into())
.concat((!1700_u128).into())
.concat((1700_u32).into())
.concat((25_u32).into())
.concat((1700_u128).into())
.concat((1900_u128).into())
.concat((1999_u128).into())
.concat((2700_u128).into())
.erase_refs_len();
println!("b: {b}");
let _ = b
.erase_len()
.concat((1700_u128).into())
.expect_err("the space in builder is insufficient");
// println!("c: {c:?}");
// println!("{:?}", b.erase_len());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment