Upload files to "/"

First instances of custom KosherTypes.

Includes:
- Decimal (incomplete math ops at the moment)

Excludes:
- Primitive datatypes

KosherC will eventually have most of the primitive types found in most languages.
This commit is contained in:
cxptbry
2026-09-13 21:10:45 -04:00
parent dd862b0fd0
commit d3652d1ea8
+456
View File
@@ -0,0 +1,456 @@
#[derive(Debug, Clone, Copy)]
enum BCHErrors {
ArgumentExceedsHexBounds,
ByteExceedsHexBounds,
BytesUninitalized,
DoubleNullByteArgs, // Fatal
IndexOutOfBounds,
StrExceedsHexBounds,
}
#[derive(Debug, Clone, Copy)]
enum BCHByteConditions {
NullConditionFlag,
DecompressionLeftNullByteFlag, // Tell the decompressor to ignore the first 4 bits of the target byte.
}
#[derive(Debug, Clone, Copy)]
pub struct BCH<const N: usize> { // Binary-coded Hex
bytes: Option<[u8; N]>
}
impl<const N: usize> BCH<N> {
pub const fn initalize() -> Self { BCH { bytes: Some([0u8; N]) } }
/// Delete all bytes and retain the BCH object
pub const fn delete_data(&mut self) -> &Self { self.bytes = None; self }
pub const fn compress_byte(&mut self, a: Option<u8>, b: Option<u8>, i: usize, conditions_only: bool) -> Result<(&Self, BCHByteConditions), BCHErrors> {
// Catch fatal errors
match (a, b) {
(None, Some(b)) => { if b > 15 { return Err(BCHErrors::ArgumentExceedsHexBounds) } }
(Some(a), None) => { if a > 15 { return Err(BCHErrors::ArgumentExceedsHexBounds) } }
(None, None) => { return Err(BCHErrors::DoubleNullByteArgs) }
(Some(a), Some(b)) => { if a > 15 || b > 15 { return Err(BCHErrors::ArgumentExceedsHexBounds) } }
};
match &mut self.bytes {
Some(bytes) => {
if i < N {
let mut condition_flag = BCHByteConditions::NullConditionFlag;
match (a, b) {
(None, Some(b)) => {
if !conditions_only { bytes[i] = b };
condition_flag = BCHByteConditions::DecompressionLeftNullByteFlag;
// println!("none, some");
}
(Some(a), None) => {
if !conditions_only {bytes[i] = a };
condition_flag = BCHByteConditions::DecompressionLeftNullByteFlag;
// println!("some, none");
}
(Some(a), Some(b)) => { // Default path
if !conditions_only { bytes[i] = (a << 4) + b };
self.bytes.unwrap()[i] = bytes[i];
condition_flag = BCHByteConditions::NullConditionFlag;
// println!("some, some")
}
_ => {
//println!("none, none. Should have err'd.")
}
}
Ok((self, condition_flag))
} else {
Err(BCHErrors::IndexOutOfBounds)
}
}
None => { Err(BCHErrors::BytesUninitalized) }
}
}
/// Take a IEEE-754 u8 and represent that number as a string.
/// This function accepts ranges between 0 to 15 to enable ease of conversion from floating-point IEEE-754 formats to BCH.
///
/// For example:
///
/// let x: u8 = 15;
///
/// let str: &str = byte_to_str(x);
///
/// assert_eq!("15", str);
pub const fn byte_to_str(&self, byte: u8) -> Result<&'static str, BCHErrors> {
match byte {
0 => { Ok("0") }
1 => { Ok("1") }
2 => { Ok("2") }
3 => { Ok("3") }
4 => { Ok("4") }
5 => { Ok("5") }
6 => { Ok("6") }
7 => { Ok("7") }
8 => { Ok("8") }
9 => { Ok("9") }
10 => { Ok("10") }
11 => { Ok("11") }
12 => { Ok("12") }
13 => { Ok("13") }
14 => { Ok("14") }
15 => { Ok("15") }
_ => { Err(BCHErrors::ByteExceedsHexBounds) }
}
}
/// Convert a &str into a BCH byte.
pub const fn compress_byte_from_str(&self, str: &str) -> Result<&Self, BCHErrors> {
Ok(self)
}
pub const fn decompress_bytes(&self, bch_conditions: Option<[BCHByteConditions; N]>) -> Result<[Option<u8>; N*2], BCHErrors> where [(); N*2]: {
// If none, then compress and decompress bytes to extract their BCHByteConditions to avoid forcing
// BCH<N> to have [u24; N] instead of [u8; N] and lose memory efficiency.
// NOTE: (I should be able to get away with this since the compiler is compile-time friendly)
//println!("{bch_conditions:?}");
let conditions: [BCHByteConditions; N] = match bch_conditions {
Some(array) => {
// println!("conditions_container: {bch_conditions:?}");
array
}
None => {
// println!("Generating conditions");
// Extract BCHByteConditions (inefficient)
let mut conditions_container: [BCHByteConditions; N] = [BCHByteConditions::NullConditionFlag; N];
let mut i = 0;
let mut binding: BCH<N> = BCH::initalize();
while i < N {
let byte = self.bytes.unwrap()[i];
let a = Some( byte >> 4);
let mut b = Some(byte & MASK);
if i == N - 1 { b = None } // If b is the last one in all the bytes and its value is 0,
// we can infer that it is none and continue using our regular compression algorithm.
// Error occurs because I forgot to decompress the BCH byte while continuing to pass it like a regular byte.
// println!("ERROR CAUSED BY BYTE {byte}");
match binding.compress_byte(a, b, i, true) {
Ok(flag) => { conditions_container[i] = flag.1; }
Err(e) => {
// println!("COMPRESSION ERROR {e:?}");
return Err(e) }
};
i += 1;
}
conditions_container
}
};
// println!("conditions_container: {conditions:?}");
let mut output_container: [Option<u8>; N*2] = [None; N*2];
const MASK: u8 = 0b00001111;
let bytes = self.bytes.unwrap();
let mut i = 0;
while i < N {
let target_byte = bytes[i];
match conditions[i] {
BCHByteConditions::NullConditionFlag => {
let a = target_byte >> 4;
let b = target_byte & MASK;
// println!("target: {:08b} | a: {} | b: {}", target_byte, a, b);
// println!("NULL CONDITION | a: {a} b: {b}");
output_container[i*2] = Some(a);
output_container[i*2+1] = Some(b);
}
BCHByteConditions::DecompressionLeftNullByteFlag => {
//todo!("Complete this conversion algorithm or implement BCHByteConditions scanning inside of self.convert_to_fp() instead. Maybe shift left by 4 bits on DLNB-flags so it turns 00001011 into 10110000 and leaves the 0 behind it to be discarded?");
// println!("DLNB target: {:08b}", target_byte);
// Test if regular decompression method is necessary to prevent byte misinterpretation.
if target_byte > 15 {
let a = target_byte >> 4;
let b = target_byte & MASK;
output_container[i*2] = Some(a);
output_container[i*2+1] = Some(b);
} else {
// println!("DLNB CONDITION | a: {target_byte} b: None");
output_container[i*2] = Some(target_byte);
output_container[i*2+1] = None;
}
}
}
i += 1;
}
// println!("output_container: {:?}", output_container);
Ok(output_container)
}
pub fn print_raw(&self) -> () { for byte in self.bytes.unwrap() { println!("{:08b}", byte)} }
pub fn print(&self) -> () { for byte in self.bytes.unwrap() { print!("{byte}")} }
}
#[derive(Debug, Clone, Copy)]
pub struct Decimal<const E: usize, const M: usize> {
exp: BCH<E>,
man: BCH<M>,
pow: i8,
}
impl<const E: usize, const M: usize> Decimal<E, M> {
pub const fn initalize(exp_arg: [(Option<u8>, Option<u8>); E], man_arg: [(Option<u8>, Option<u8>); M], sign: bool) -> Self {
let mut exp = BCH::<E>::initalize();
let mut man = BCH::<M>::initalize();
let mut i = 0;
while i < E {
// Load exponent
let a = exp_arg[i].0;
let b = exp_arg[i].1;
match exp.compress_byte(a, b, i, false) {
Ok(_) => {
//println!("compression successful | exp");
}
Err(_) => { panic!("Load Binary-Coded Hexadecimal Byte failed | EXP\nDebug suggestion: Did you enter a number within the range of 0..=15?") }
};
i += 1;
}
i = 0;
while i < M {
// Load mantissa
let a = man_arg[i].0;
let b = man_arg[i].1;
match man.compress_byte(a, b, i, false) {
Ok(_) => {
// println!("compression successful | man");
}
Err(_) => { panic!("Load Binary-Coded Hexadecimal Byte failed | MAN\nDebug suggestion: Did you enter a number within the range of 0..=15?") }
};
i += 1;
}
// println!("EXP {exp:?} MAN {man:?}");
let sign_bit: i8 = if sign { -1 } else { 1 };
// Prevent decimal -> f64 conversion edgecasing when M = 0.
let final_pow: i8 = if M != 0 { M as i8 * sign_bit} else { sign_bit };
Decimal { exp: exp, man: man, pow: final_pow, }
}
pub const fn convert_to_fp_num(&self) -> f64 where [(); E*2]:, [(); M*2]: {
let mut i: usize = 0;
let mut exp_f64: u16 = 0;
if E > 0 {
match self.exp.decompress_bytes(None) {
Ok(bytes) => {
// Limit i from exceeding 4 digits (preventing buffer overflows).
// Assume the equation of Val * 10^pow(max - i)
let mut max: usize = if E*2 <= 3 { E*2 } else { 3 };
let mut j = 0;
while j < E*2 {
match bytes[j] {
None => { if max > 0 { max -= 1; } }
_ => { }
}
j += 1;
}
let mut pow_factor = 0;
// println!("max: {max}");
while i < max {
let byte = bytes[i];
match byte {
Some(val) => {
let byte = val as u16;
// println!("this byte is a some value");
match byte {
0..=9 => { pow_factor += 1; }
10..=15 => { pow_factor += 2; }
_ => {}
}
let increment = byte * 10_u16.pow((max - pow_factor) as u32);
// println!("{byte} * 10^{max} - {pow_factor} = {increment}");
// println!("{future_exp_f64}");
// If exp_f64 will exceed the bounds of -1022 to +1023, do not append more data.
let pos_safe: bool = exp_f64 <= 1023 && self.pow >= 1;
let neg_safe: bool = exp_f64 <= 1022 && self.pow <= -1;
// println!("pos_safe: {pos_safe} | neg_safe: {neg_safe}");
if pos_safe || neg_safe {
exp_f64 += increment;
// println!("exp_f64: {exp_f64} {i}");
} else {
if self.pow <= 1 { exp_f64 = 1022 } else { exp_f64 = 1023 };
// println!("break");
break;
}
}
None => {
// println!("this byte is a none value")
}
};
i += 1;
}
}
Err(_) => {
// println!("fp_num_decompression failed. Bytes do not exist. | EXP");
// panic!("Attempted to convert uninitalized Decimal ({self:?}) to a floating-point number.\n Debug Suggestion: Try verifying the exponent bits.");
}
};
i = 0;
}
let mut man_f64: f64 = 0.0;
if M > 0 {
match self.man.decompress_bytes(None) {
Ok(bytes) => {
// Limit i from exceeding 38 digits (preventing buffer overflows and inaccuracy).
// Assume the equation of Val / 10^pow(pow_factor)
let mut max = if self.pow <= 38 { (self.pow.abs() * 2) as usize } else { 38 };// M*2;
let mut j = 0;
while j < M*2 {
match bytes[j] {
None => { if max > 0 { max -= 1; } }
_ => { }
}
j += 1;
}
let mut pow_factor: u32 = 0;
let mut increment: f64 = 0.0;
while i < max {
match bytes[i] {
Some(val) => {
let byte = val as u16;
match byte {
0..=9 => { pow_factor += 1; }
10..=15 => { pow_factor += 2; }
_ => {}
}
// Ensure pow_factor doesn't unintentionally exceed the 38th power to avoid overflow errors.
if pow_factor <= 38 {
increment = byte as f64 / 10_u128.pow(pow_factor) as f64;
// println!("{:?} / 10^{} = {increment}", bytes[i], pow_factor);
man_f64 += increment;
} else {
break;
}
// todo!("Fix this math lol");
// If man_f64 will exceed 52 digits, do not append more data.
}
None => { }
_ => {}
};
i += 1;
}
// println!("{man_f64}");
}
Err(_) => {
// println!("fp_num_decompression failed. Bytes do not exist. | MAN");
// panic!("Attempted to convert uninitalized Decimal ({self:?}) to a floating-point number.\n Debug Suggestion: Try verifying the exponent bits.");
}
};
}
let mut final_f64: f64 = exp_f64 as f64 + man_f64;
//println!("final_f64 {final_f64}");
if self.pow <= -1 { final_f64 *= -1.0 }; // If negative, flip its sign bit.
//println!("self.pow: {}", self.pow);
// println!("Final converted value. {:?} -> {final_f64}", self.print());
final_f64
}
pub const fn memory_cost(&self) -> usize where [(); E*2]:, [(); M*2]: {
let exponent_cost_as_bits = E * 8;
let mantissa_cost_as_bits = M * 8;
let power_cost_as_bits = 8;
let sum = exponent_cost_as_bits + mantissa_cost_as_bits + power_cost_as_bits;
sum
}
pub fn print_raw(&self) -> () { self.exp.print_raw(); self.man.print_raw(); println!("pow: {}", self.pow); }
pub fn print(&self) -> () where [(); E*2]:, [(); M*2]: {
if self.pow <= -1 { print!("-") }
match self.exp.decompress_bytes(None) {
Ok(bytes) => {
if bytes.len() == 0 { print!("0"); }
else {
for byte in bytes {
match byte { Some(val) => print!("{val:?}"),
None => { }
}
}
}
}
Err(_) => { print!("0"); }
}
print!(".");
match self.man.decompress_bytes(None) {
Ok(bytes) => {
if bytes.len() == 0 { print!("0"); }
else {
for byte in bytes {
match byte { Some(val) => print!("{val:?}"),
None => { }
}
}
}
}
Err(_) => { print!("0"); }
}
println!();
}
}