mesh_loader/utils/
int.rs
1#![allow(
6 clippy::cast_possible_truncation,
7 clippy::cast_possible_wrap,
8 clippy::cast_sign_loss
9)]
10
11use self::integer::RawInteger;
12use crate::utils::float::{common::ByteSlice, parse::try_parse_digits};
13
14#[inline]
15pub fn parse<T: Integer>(bytes: &[u8]) -> Option<T> {
16 T::parse(bytes)
17}
18
19#[inline]
20pub fn parse_partial<T: Integer>(bytes: &[u8]) -> Option<(T, usize)> {
21 T::parse_partial(bytes)
22}
23
24mod integer {
25 pub trait RawInteger: Copy {
26 const MAX_DIGITS: usize;
27 const MIN_SAFE: u64;
28 const MAX: u64;
29 const IS_SIGNED: bool;
30 fn from_u64(v: u64, negative: bool) -> Self;
31 }
32}
33
34pub trait Integer: integer::RawInteger {
35 #[inline]
36 fn parse(bytes: &[u8]) -> Option<Self> {
37 match Self::parse_partial(bytes) {
38 Some((v, n)) if n == bytes.len() => Some(v),
39 _ => None,
40 }
41 }
42 #[inline]
43 fn parse_partial(bytes: &[u8]) -> Option<(Self, usize)> {
44 dec2int(bytes)
45 }
46}
47
48const BASE: u8 = 10;
49
50macro_rules! max_digit_count {
51 ($ty:ident) => {{
52 let mut max = $ty::MAX;
53 let mut count = 0;
54 while max > 0 {
55 count += 1;
56 max /= BASE as $ty;
57 }
58 count
59 }};
60}
61
62macro_rules! uint {
63 ($ty:ident) => {
64 impl RawInteger for $ty {
65 const MAX_DIGITS: usize = max_digit_count!($ty);
66 const MIN_SAFE: u64 = (BASE as u64).pow($ty::MAX_DIGITS as u32 - 1);
67 const MAX: u64 = $ty::MAX as u64;
68 const IS_SIGNED: bool = false;
69 #[inline]
70 fn from_u64(v: u64, negative: bool) -> Self {
71 debug_assert!(!negative);
72 v as $ty
73 }
74 }
75 impl Integer for $ty {}
76 };
77}
78macro_rules! int {
79 ($ty:ident) => {
80 impl RawInteger for $ty {
81 const MAX_DIGITS: usize = max_digit_count!($ty);
82 const MIN_SAFE: u64 = (BASE as u64).pow($ty::MAX_DIGITS as u32 - 1);
83 const MAX: u64 = $ty::MAX as u64;
84 const IS_SIGNED: bool = true;
85 #[inline]
86 fn from_u64(v: u64, negative: bool) -> Self {
87 if negative {
88 (-$ty::MAX).wrapping_sub((v.wrapping_sub($ty::MAX as u64)) as $ty)
89 } else {
90 v as $ty
91 }
92 }
93 }
94 impl Integer for $ty {}
95 };
96}
97uint!(u64);
99uint!(u32);
100uint!(u16);
101uint!(u8);
102int!(i64);
104int!(i32);
105int!(i16);
106int!(i8);
107
108#[inline]
109fn dec2int<I: RawInteger>(mut s: &[u8]) -> Option<(I, usize)> {
110 let start = s;
111 let c = if let Some(&c) = s.first() {
112 c
113 } else {
114 return None;
115 };
116 let negative;
117 if I::IS_SIGNED {
118 negative = c == b'-';
119 if negative || c == b'+' {
120 s = &s[1..];
121 if s.is_empty() {
122 return None;
123 }
124 }
125 } else {
126 negative = false;
127 if c == b'+' {
128 s = &s[1..];
129 if s.is_empty() {
130 return None;
131 }
132 }
133 }
134
135 let (v, len) = parse_partial_number(s, start, negative, I::MAX_DIGITS, I::MIN_SAFE, I::MAX)?;
136 Some((I::from_u64(v, negative), len))
137}
138
139#[inline(always)]
140fn parse_partial_number(
141 mut s: &[u8],
142 full_start: &[u8],
143 negative: bool,
144 max_digits: usize,
145 min_safe: u64,
146 max: u64,
147) -> Option<(u64, usize)> {
148 debug_assert!(!s.is_empty());
149
150 let start = s;
152 while let [b'0', s_next @ ..] = s {
156 s = s_next;
157 }
158
159 let mut v = 0_u64;
161 let digits_start = s;
162 if max_digits >= 8 {
163 try_parse_digits(&mut s, &mut v);
164 } else {
165 s = s.parse_digits(|digit| {
166 v = v.wrapping_mul(10).wrapping_add(digit as u64);
167 });
168 }
169 let n_digits = s.offset_from(digits_start) as usize;
170
171 if n_digits == 0 && s.offset_from(start) == 0 {
172 return None;
173 }
174
175 if n_digits > max_digits {
177 return None;
178 }
179 if n_digits == max_digits && v < min_safe {
180 return None;
181 }
182 if max != u64::MAX && v > max + negative as u64 {
183 return None;
184 }
185
186 let len = s.offset_from(full_start) as usize;
187 Some((v, len))
188}
189
190#[cfg(test)]
191#[path = "tests/int.rs"]
192mod tests;