xsd_types/lexical/decimal/
integer.rs1use crate::lexical::lexical_form;
2
3use super::{Decimal, DecimalBuf, Overflow, Sign};
4use std::borrow::{Borrow, ToOwned};
5use std::cmp::Ordering;
6use std::fmt;
7use std::hash::{Hash, Hasher};
8use std::str::FromStr;
9
10mod non_negative_integer;
11mod non_positive_integer;
12
13pub use non_negative_integer::*;
14pub use non_positive_integer::*;
15
16lexical_form! {
17 ty: Integer,
21
22 buffer: IntegerBuf,
26
27 new,
32
33 new_unchecked,
39
40 value: crate::Integer,
41 error: InvalidInteger,
42 as_ref: as_integer,
43 parent_forms: {
44 as_decimal: Decimal, DecimalBuf
45 }
46}
47
48impl Integer {
49 pub fn is_positive(&self) -> bool {
52 let mut sign_positive = true;
53 for c in &self.0 {
54 match c {
55 b'+' | b'0' => (),
56 b'-' => sign_positive = false,
57 _ => return sign_positive,
58 }
59 }
60
61 false
62 }
63
64 pub fn is_negative(&self) -> bool {
67 let mut sign_negative = true;
68 for c in &self.0 {
69 match c {
70 b'-' | b'0' => (),
71 b'+' => sign_negative = false,
72 _ => return sign_negative,
73 }
74 }
75
76 false
77 }
78
79 pub fn is_zero(&self) -> bool {
82 for c in &self.0 {
83 if !matches!(c, b'+' | b'-' | b'0') {
84 return false;
85 }
86 }
87
88 true
89 }
90
91 pub fn is_non_negative(&self) -> bool {
94 self.0[0] != b'-'
95 }
96
97 pub fn sign(&self) -> Sign {
98 let mut sign_positive = true;
99 for c in &self.0 {
100 match c {
101 b'+' | b'0' => (),
102 b'-' => sign_positive = false,
103 _ => {
104 if sign_positive {
105 return Sign::Positive;
106 } else {
107 return Sign::Negative;
108 }
109 }
110 }
111 }
112
113 Sign::Zero
114 }
115
116 pub fn abs(&self) -> &NonNegativeInteger {
120 let mut last_zero = 0;
121 for (i, c) in self.0.iter().enumerate() {
122 match c {
123 b'+' | b'-' => (),
124 b'0' => last_zero = i,
125 _ => return unsafe { NonNegativeInteger::new_unchecked(&self.0[i..]) },
126 }
127 }
128
129 unsafe { NonNegativeInteger::new_unchecked(&self.0[last_zero..]) }
130 }
131
132 pub fn canonical(&self) -> &Self {
134 if self.is_zero() {
135 unsafe { Self::new_unchecked(&self.0[self.0.len() - 1..]) }
136 } else {
137 let mut last_zero = 0;
138 for (i, c) in self.0.iter().enumerate() {
139 match c {
140 b'+' => (),
141 b'0' => last_zero = i,
142 _ => return unsafe { Self::new_unchecked(&self.0[i..]) },
143 }
144 }
145
146 unsafe { Self::new_unchecked(&self.0[last_zero..]) }
147 }
148 }
149
150 #[inline(always)]
151 fn as_canonical_str(&self) -> &str {
152 self.canonical().as_str()
153 }
154
155 #[inline(always)]
156 pub fn value(&self) -> crate::Integer {
157 crate::Integer::from_str(self.as_str()).unwrap()
158 }
159}
160
161impl PartialEq for Integer {
162 fn eq(&self, other: &Self) -> bool {
163 self.as_canonical_str() == other.as_canonical_str()
164 }
165}
166
167impl Eq for Integer {}
168
169impl Hash for Integer {
170 fn hash<H: Hasher>(&self, h: &mut H) {
171 self.as_canonical_str().hash(h)
172 }
173}
174
175impl Ord for Integer {
176 fn cmp(&self, other: &Self) -> Ordering {
177 let sign = self.sign();
178 let other_sign = other.sign();
179 match sign.cmp(&other_sign) {
180 Ordering::Equal => {
181 let a = self.abs().as_bytes();
182 let b = other.abs().as_bytes();
183
184 match a.len().cmp(&b.len()) {
185 Ordering::Equal => {
186 if sign.is_negative() {
187 a.cmp(b).reverse()
188 } else {
189 a.cmp(b)
190 }
191 }
192 other => {
193 if sign.is_negative() {
194 other.reverse()
195 } else {
196 other
197 }
198 }
199 }
200 }
201 other => other,
202 }
203 }
204}
205
206impl PartialOrd for Integer {
207 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
208 Some(self.cmp(other))
209 }
210}
211
212impl IntegerBuf {
213 pub fn zero() -> Self {
214 unsafe { Self::new_unchecked("0".to_string()) }
215 }
216
217 pub fn one() -> Self {
218 unsafe { Self::new_unchecked("1".to_string()) }
219 }
220}
221
222impl Default for IntegerBuf {
223 fn default() -> Self {
224 Self::zero()
225 }
226}
227
228impl PartialOrd for IntegerBuf {
229 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
230 Some(self.cmp(other))
231 }
232}
233
234impl Ord for IntegerBuf {
235 fn cmp(&self, other: &Self) -> Ordering {
236 self.as_integer().cmp(other.as_integer())
237 }
238}
239
240macro_rules! number_conversion {
241 { $($ty:ty),* } => {
242 $(
243 impl From<$ty> for IntegerBuf {
244 fn from(i: $ty) -> Self {
245 unsafe { IntegerBuf::new_unchecked(i.to_string()) }
246 }
247 }
248
249 impl<'a> TryFrom<&'a Integer> for $ty {
250 type Error = Overflow;
251
252 fn try_from(i: &'a Integer) -> Result<Self, Overflow> {
253 i.as_str().parse().map_err(|_| Overflow)
254 }
255 }
256
257 impl TryFrom<IntegerBuf> for $ty {
258 type Error = Overflow;
259
260 fn try_from(i: IntegerBuf) -> Result<Self, Overflow> {
261 i.as_str().parse().map_err(|_| Overflow)
262 }
263 }
264 )*
265 };
266}
267
268number_conversion! {
269 u8,
270 i8,
271 u16,
272 i16,
273 u32,
274 i32,
275 u64,
276 i64,
277 u128,
278 i128,
279 usize,
280 isize
281}
282
283fn check_bytes(s: &[u8]) -> bool {
284 check(s.iter().copied())
285}
286
287fn check<C: Iterator<Item = u8>>(mut chars: C) -> bool {
288 enum State {
289 Initial,
290 NonEmptyInteger,
291 Integer,
292 }
293
294 let mut state = State::Initial;
295
296 loop {
297 state = match state {
298 State::Initial => match chars.next() {
299 Some(b'+') => State::NonEmptyInteger,
300 Some(b'-') => State::NonEmptyInteger,
301 Some(b'0'..=b'9') => State::Integer,
302 _ => break false,
303 },
304 State::NonEmptyInteger => match chars.next() {
305 Some(b'0'..=b'9') => State::Integer,
306 _ => break false,
307 },
308 State::Integer => match chars.next() {
309 Some(b'0'..=b'9') => State::Integer,
310 Some(_) => break false,
311 None => break true,
312 },
313 }
314 }
315}
316
317#[cfg(test)]
318mod tests {
319 use super::*;
320
321 #[test]
322 fn parse_01() {
323 Integer::new("0").unwrap();
324 }
325
326 #[test]
327 #[should_panic]
328 fn parse_02() {
329 Integer::new("+").unwrap();
330 }
331
332 #[test]
333 #[should_panic]
334 fn parse_03() {
335 Integer::new("-").unwrap();
336 }
337
338 #[test]
339 #[should_panic]
340 fn parse_04() {
341 Integer::new("012+").unwrap();
342 }
343
344 #[test]
345 fn parse_05() {
346 Integer::new("+42").unwrap();
347 }
348
349 #[test]
350 fn parse_06() {
351 Integer::new("-42").unwrap();
352 }
353
354 #[test]
355 fn abs_01() {
356 assert_eq!(Integer::new("01").unwrap().abs().as_str(), "1")
357 }
358
359 #[test]
360 fn abs_02() {
361 assert_eq!(Integer::new("00").unwrap().abs().as_str(), "0")
362 }
363
364 #[test]
365 fn abs_03() {
366 assert_eq!(Integer::new("+00000").unwrap().abs().as_str(), "0")
367 }
368
369 #[test]
370 fn abs_04() {
371 assert_eq!(Integer::new("-00000").unwrap().abs().as_str(), "0")
372 }
373
374 #[test]
375 fn abs_05() {
376 assert_eq!(Integer::new("-00100").unwrap().abs().as_str(), "100")
377 }
378
379 #[test]
380 fn eq_01() {
381 assert_eq!(Integer::new("+001").unwrap(), Integer::new("1").unwrap())
382 }
383
384 #[test]
385 fn eq_02() {
386 assert_ne!(Integer::new("-001").unwrap(), Integer::new("1").unwrap())
387 }
388
389 #[test]
390 fn eq_03() {
391 assert_eq!(Integer::new("-000").unwrap(), Integer::new("+0").unwrap())
392 }
393
394 #[test]
395 fn cmp_01() {
396 assert!(Integer::new("123").unwrap() < Integer::new("456").unwrap())
397 }
398
399 #[test]
400 fn cmp_02() {
401 assert!(Integer::new("1230").unwrap() > Integer::new("456").unwrap())
402 }
403
404 #[test]
405 fn cmp_03() {
406 assert!(Integer::new("-1230").unwrap() < Integer::new("456").unwrap())
407 }
408
409 #[test]
410 fn cmp_04() {
411 assert!(Integer::new("-1230").unwrap() < Integer::new("-456").unwrap())
412 }
413
414 #[test]
415 fn cmp_05() {
416 assert!(Integer::new("-123").unwrap() > Integer::new("-456").unwrap())
417 }
418
419 #[test]
420 fn cmp_06() {
421 assert_eq!(
422 Integer::new("+123456")
423 .unwrap()
424 .cmp(Integer::new("0000123456").unwrap()),
425 Ordering::Equal
426 )
427 }
428}