Created
November 24, 2022 21:35
-
-
Save DutchGhost/112ab45cda7ed2b85ac34475a43bbd22 to your computer and use it in GitHub Desktop.
Parsed. Const parsing of strings to integral types
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
#![feature(const_for)] | |
#![feature(const_refs_to_cell)] | |
#![feature(const_trait_impl)] | |
#![feature(generic_const_exprs)] | |
use { | |
core::{ | |
ops::{Div, Mul, Not, Add} | |
}, | |
}; | |
trait Properties: | |
~const From<u8> + | |
~const PartialEq + | |
~const PartialOrd + | |
~const Mul<Output = Self> + | |
~const Div<Output = Self> + | |
~const Not<Output = Self> + | |
Copy | |
{ | |
const ZERO: Self = Self::from(0u8); | |
const MAX: Self = !Self::from(0u8); | |
const DIGITS10: usize = { | |
let ten = Self::from(10); | |
let multipliers = [ | |
ten, | |
ten * ten, | |
ten * ten * ten, | |
ten * ten * ten * ten | |
]; | |
let mut result: usize = 1; | |
let mut current = Self::MAX; | |
loop { | |
if current < multipliers[0] { break result } | |
if current < multipliers[1] { break result + 1 } | |
if current < multipliers[2] { break result + 2 } | |
if current < multipliers[3] { break result + 3 } | |
current = current / multipliers[3]; | |
result += 4; | |
} | |
}; | |
} | |
impl <T> Properties for T where T: | |
~const From<u8> + | |
~const PartialEq + | |
~const PartialOrd + | |
~const Mul<Output = Self> + | |
~const Div<Output = Self> + | |
~const Not<Output = Self> + | |
Copy | |
{} | |
trait Table: | |
Properties + | |
~const From<u8> + | |
~const Mul<Output = Self> | |
where | |
[(); <Self as Properties>::DIGITS10]: | |
{ | |
const TABLE: [Self; Self::DIGITS10] = { | |
let mut a = [Self::from(0); Self::DIGITS10]; | |
let multiplier: Self = Self::from(10u8); | |
let mut current: Self = Self::from(1u8); | |
let mut idx = <Self as Properties>::DIGITS10 - 1; | |
// do while... | |
while { | |
a[idx] = current; | |
idx != 0 | |
} | |
{ | |
current = current * multiplier; | |
idx -= 1; | |
} | |
a | |
}; | |
} | |
impl <T> Table for T where T: | |
Properties + | |
~const Default + | |
~const From<u8> + | |
~const Mul<Output = Self>, | |
[(); <Self as Properties>::DIGITS10]: | |
{} | |
#[derive(Clone, Copy, Debug)] | |
enum ParseIntError { | |
InvalidDigit, | |
} | |
const fn parse_byte<T>(b: u8, pow10: T) -> Result<T, ParseIntError> | |
where | |
T: ~const From<u8> + ~const Mul<Output = T> + Copy, | |
{ | |
let r = b.wrapping_sub(48); | |
if r > 9 { | |
Err(ParseIntError::InvalidDigit) | |
} else { | |
Ok(T::from(r) * pow10) | |
} | |
} | |
const fn parse<T>(b: &str) -> Result<T, ParseIntError> | |
where | |
T: Table + | |
Properties + | |
~const From<u8> + | |
~const Mul<Output = T> + | |
~const Add<Output = T>, | |
[(); <T as Properties>::DIGITS10]: | |
{ | |
let bytes = b.as_bytes(); | |
let mut result: T = T::ZERO; | |
let len = bytes.len(); | |
// Start at the correct index of the table, | |
// (skip the power's that are too large) | |
let mut index_const_table = <T as Table>::TABLE.len() - len; | |
let mut index = 0; | |
while index < b.len() { | |
let a = bytes[index]; | |
let p = <T as Table>::TABLE[index_const_table]; | |
let r = match parse_byte(a, p) { | |
Err(e) => return Err(e), | |
Ok(d) => d, | |
}; | |
result = result + r; | |
index += 1; | |
index_const_table += 1; | |
} | |
Ok(result) | |
} | |
const fn unwarp<T: Copy>(opt: Result<T, ParseIntError>) -> T { | |
match opt { | |
Ok(t) => t, | |
_ => loop {} | |
} | |
} | |
const A: u16 = unwarp(parse::<u16>("1234")); | |
const B: u32 = unwarp(parse::<u32>("1234")); | |
const C: u64 = unwarp(parse::<u64>("1234")); | |
const D: usize = unwarp(parse::<usize>("1234")); | |
fn main() { | |
dbg!(A, B, C, D); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment