const_str/__ctfe/
parse.rs1use core::marker::PhantomData;
2
3pub struct Parse<T, U>(T, PhantomData<fn(T) -> U>);
4
5impl<T, U> Parse<T, U> {
6 pub const fn new(t: T) -> Self {
7 Self(t, PhantomData)
8 }
9}
10
11impl Parse<&str, bool> {
12 pub const fn const_eval(&self) -> bool {
13 if crate::str::equal(self.0, "true") {
14 return true;
15 }
16 if crate::str::equal(self.0, "false") {
17 return false;
18 }
19 panic!("parse error")
20 }
21}
22
23impl Parse<&str, &str> {
24 pub const fn const_eval(&self) -> &str {
25 self.0
26 }
27}
28
29impl Parse<&str, char> {
30 pub const fn const_eval(&self) -> char {
31 let s = self.0.as_bytes();
32 if let Some((ch, count)) = crate::utf8::next_char(s) {
33 if count == s.len() {
34 return ch;
35 }
36 }
37 panic!("parse error")
38 }
39}
40
41trait IsSignedInteger {
42 const OUTPUT: bool;
43}
44
45macro_rules! mark_signed_integer {
46 ($s: expr, $($ty:ty),+) => {
47 $(
48 impl IsSignedInteger for $ty {
49 const OUTPUT: bool = $s;
50 }
51 )+
52 }
53}
54
55mark_signed_integer!(true, i8, i16, i32, i64, i128, isize);
56mark_signed_integer!(false, u8, u16, u32, u64, u128, usize);
57
58macro_rules! impl_integer_parse {
59 ($($ty: ty),+) => {$(
60 impl Parse<&str, $ty> {
61 pub const fn const_eval(&self) -> $ty {
62 let s = self.0.as_bytes();
63 let is_signed = <$ty as IsSignedInteger>::OUTPUT;
64 let (is_positive, digits) = match s {
65 [] => panic!("parse error"),
66 [x, xs @ ..] => match x {
67 b'+' => (true, xs),
68 b'-' if is_signed => (false, xs),
69 _ => (true, s),
70 },
71 };
72
73 let mut ans: $ty = 0;
74 let mut i = 0;
75 while i < digits.len() {
76 let x = crate::ascii::num_from_dec_digit(digits[i]);
77
78 match ans.checked_mul(10) {
79 Some(val) => {
80 let val = if is_positive {
81 val.checked_add(x as _)
82 } else {
83 val.checked_sub(x as _)
84 };
85 match val {
86 Some(val) => ans = val,
87 None => panic!("parse error"),
88 }
89 }
90 None => panic!("parse error"),
91 };
92
93 i += 1;
94 }
95
96 ans
97 }
98 }
99 )+};
100}
101
102impl_integer_parse!(u8, u16, u32, u64, u128, usize);
103impl_integer_parse!(i8, i16, i32, i64, i128, isize);
104
105#[macro_export]
133macro_rules! parse {
134 ($s: expr, $ty: ty) => {{
135 $crate::__ctfe::Parse::<_, $ty>::new($s).const_eval()
136 }};
137}
138
139#[cfg(test)]
140mod tests {
141 #[test]
142 fn test_parse() {
143 macro_rules! test_parse {
144 ($s: expr, $ty: tt) => {{
145 const OUTPUT: $ty = $crate::parse!($s, $ty);
146 let ans: $ty = $s.parse().unwrap();
147 assert_eq!(OUTPUT, ans)
148 }};
149 }
150
151 test_parse!("true", bool);
152 test_parse!("false", bool);
153
154 test_parse!("啊", char);
155
156 test_parse!("0", u8);
157 test_parse!("-1", i8);
158 test_parse!("+42000", u32);
159 test_parse!("-42000", i32);
160 }
161}