Created
September 16, 2024 16:23
-
-
Save ProgramCrafter/c79293307b7df0740b87ae244072a4d3 to your computer and use it in GitHub Desktop.
This file contains hidden or 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(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