1#![warn(clippy::all, clippy::pedantic, clippy::undocumented_unsafe_blocks)]
2#![allow(
3 clippy::let_underscore_untyped,
4 reason = "https://github.com/rust-lang/rust-clippy/pull/10442#issuecomment-1516570154"
5)]
6#![allow(
7 clippy::question_mark,
8 reason = "https://github.com/rust-lang/rust-clippy/issues/8281"
9)]
10#![allow(clippy::manual_let_else, reason = "manual_let_else was very buggy on release")]
11#![allow(clippy::missing_errors_doc, reason = "A lot of existing code fails this lint")]
12#![allow(
13 clippy::module_name_repetitions,
14 reason = "incompatible with how code is organized in private modules"
15)]
16#![allow(
17 clippy::unnecessary_lazy_evaluations,
18 reason = "https://github.com/rust-lang/rust-clippy/issues/8109"
19)]
20#![cfg_attr(
21 test,
22 allow(clippy::non_ascii_literal, reason = "tests sometimes require UTF-8 string content")
23)]
24#![allow(unknown_lints)]
25#![warn(
26 missing_copy_implementations,
27 missing_debug_implementations,
28 missing_docs,
29 rust_2024_compatibility,
30 trivial_casts,
31 trivial_numeric_casts,
32 unused_qualifications,
33 variant_size_differences
34)]
35#![cfg_attr(docsrs, feature(doc_cfg))]
40#![cfg_attr(docsrs, feature(doc_alias))]
41
42#![no_std]
64
65#[cfg(doctest)]
67#[doc = include_str!("../README.md")]
68mod readme {}
69
70extern crate alloc;
71#[cfg(feature = "std")]
72extern crate std;
73
74mod error;
75mod parser;
76mod radix;
77mod subject;
78mod whitespace;
79
80pub use error::{ArgumentError, Error, InvalidRadixError, InvalidRadixExceptionKind};
81use parser::{Sign, State as ParseState};
82use radix::RADIX_TABLE;
83pub use radix::Radix;
84use subject::IntegerString;
85
86pub fn parse<T>(subject: &T, radix: Option<i64>) -> Result<i64, Error<'_>>
177where
178 T: AsRef<[u8]> + ?Sized,
179{
180 let subject = subject.as_ref();
181 parse_inner(subject, radix)
182}
183
184fn parse_inner(subject: &[u8], radix: Option<i64>) -> Result<i64, Error<'_>> {
185 let subject = IntegerString::try_from(subject)?;
187 let radix = if let Some(radix) = radix {
189 Radix::try_base_from_str_and_i64(subject, radix)?
190 } else {
191 None
192 };
193 let mut state = ParseState::new(subject);
194
195 let mut chars = whitespace::trim(subject.as_bytes()).iter().copied().peekable();
197
198 match chars.peek() {
200 Some(b'+') => {
201 state = state.set_sign(Sign::Positive)?;
202 chars.next();
203 }
204 Some(b'-') => {
205 state = state.set_sign(Sign::Negative)?;
206 chars.next();
207 }
208 Some(_) => {}
209 None => return Err(subject.into()),
210 }
211
212 let radix = match chars.peek() {
214 Some(b'0') => {
216 chars.next();
217 match (chars.peek(), radix) {
218 (Some(b'b' | b'B'), None | Some(2)) => {
219 chars.next();
220 2
221 }
222 (Some(b'o' | b'O'), None | Some(8)) => {
223 chars.next();
224 8
225 }
226 (Some(b'd' | b'D'), None | Some(10)) => {
227 chars.next();
228 10
229 }
230 (Some(b'x' | b'X'), None | Some(16)) => {
231 chars.next();
232 16
233 }
234 (Some(b'b' | b'B' | b'o' | b'O' | b'd' | b'D' | b'x' | b'X'), Some(_)) => return Err(subject.into()),
235 (None, _) => return Ok(0),
236 (Some(_), None) => 8,
237 (Some(_), Some(radix)) => radix,
238 }
239 }
240 Some(_) => radix.unwrap_or(10),
241 None => return Err(subject.into()),
242 };
243
244 loop {
246 if chars.next_if_eq(&b'0').is_some() {
247 if chars.next_if_eq(&b'_').is_some() {
248 match chars.peek() {
249 None | Some(b'_') => return Err(subject.into()),
250 Some(_) => {}
251 }
252 }
253 } else if let Some(b'_') = chars.peek() {
254 return Err(subject.into());
255 } else {
256 break;
257 }
258 }
259
260 loop {
263 match chars.next() {
264 Some(b'_') => match chars.peek() {
265 None | Some(b'_') => return Err(subject.into()),
266 Some(_) => {}
267 },
268 Some(b) if RADIX_TABLE[usize::from(b)] <= radix => {
269 state = state.collect_digit(b);
270 }
271 Some(_) => return Err(subject.into()),
272 None => break,
273 }
274 }
275
276 let src = state.into_numeric_string()?;
278 i64::from_str_radix(&src, radix).map_err(|_| subject.into())
279}
280
281#[cfg(test)]
282mod tests {
283 use crate::parse;
284
285 #[test]
286 fn parse_int_max() {
287 let result = parse("9_223_372_036_854_775_807", None);
288 assert_eq!(result.unwrap(), i64::MAX);
289 let result = parse("+9_223_372_036_854_775_807", None);
290 assert_eq!(result.unwrap(), i64::MAX);
291 }
292
293 #[test]
294 fn parse_int_min() {
295 let result = parse("-9_223_372_036_854_775_808", None);
296 assert_eq!(result.unwrap(), i64::MIN);
297 }
298
299 #[test]
300 fn leading_zero_does_not_imply_octal_when_given_radix() {
301 let result = parse("017", Some(12));
308 assert_eq!(result.unwrap(), 19);
309 let result = parse("-017", Some(12));
310 assert_eq!(result.unwrap(), -19);
311 }
312
313 #[test]
314 fn squeeze_leading_zeros() {
315 let result = parse("0x0000000000000011", Some(16));
316 assert_eq!(result.unwrap(), 17);
317 let result = parse("-0x0000000000000011", Some(16));
318 assert_eq!(result.unwrap(), -17);
319
320 let result = parse("0x00_00000000000011", Some(16));
321 assert_eq!(result.unwrap(), 17);
322 let result = parse("-0x00_00000000000011", Some(16));
323 assert_eq!(result.unwrap(), -17);
324
325 let result = parse("0x0_0_0_11", Some(16));
326 assert_eq!(result.unwrap(), 17);
327 let result = parse("-0x0_0_0_11", Some(16));
328 assert_eq!(result.unwrap(), -17);
329
330 let result = parse("-0x00000_15", Some(16));
331 assert_eq!(result.unwrap(), -21);
332 }
333
334 #[test]
335 fn squeeze_leading_zeros_is_octal_when_octal_digits() {
336 let result = parse("000000000000000000000000000000000000000123", None);
337 assert_eq!(result.unwrap(), 83);
338 }
339
340 #[test]
341 fn squeeze_leading_is_invalid_when_non_octal_digits() {
342 parse("000000000000000000000000000000000000000987", None).unwrap_err();
343 }
344
345 #[test]
346 fn squeeze_leading_zeros_enforces_no_double_underscore() {
347 parse("0x___11", Some(16)).unwrap_err();
348 parse("-0x___11", Some(16)).unwrap_err();
349 parse("0x0___11", Some(16)).unwrap_err();
350 parse("-0x0___11", Some(16)).unwrap_err();
351 parse("0x_0__11", Some(16)).unwrap_err();
352 parse("-0x_0__11", Some(16)).unwrap_err();
353 parse("0x_00__11", Some(16)).unwrap_err();
354 parse("-0x_00__11", Some(16)).unwrap_err();
355 }
356
357 #[test]
358 fn no_digits_with_base_prefix() {
359 parse("0x", None).unwrap_err();
360 parse("0b", None).unwrap_err();
361 parse("0o", None).unwrap_err();
362 parse("o", None).unwrap_err();
363 parse("0d", None).unwrap_err();
364 parse("0X", None).unwrap_err();
365 parse("0B", None).unwrap_err();
366 parse("0O", None).unwrap_err();
367 parse("O", None).unwrap_err();
368 parse("0D", None).unwrap_err();
369 }
370
371 #[test]
372 fn no_digits_with_base_prefix_neg() {
373 parse("-0x", None).unwrap_err();
374 parse("-0b", None).unwrap_err();
375 parse("-0o", None).unwrap_err();
376 parse("-o", None).unwrap_err();
377 parse("-0d", None).unwrap_err();
378 parse("-0X", None).unwrap_err();
379 parse("-0B", None).unwrap_err();
380 parse("-0O", None).unwrap_err();
381 parse("-O", None).unwrap_err();
382 parse("-0D", None).unwrap_err();
383 }
384
385 #[test]
386 fn no_digits_with_invalid_base_prefix() {
387 parse("0z", None).unwrap_err();
388 parse("0z", Some(12)).unwrap_err();
389 }
390
391 #[test]
392 fn no_digits_with_invalid_base_prefix_neg() {
393 parse("-0z", None).unwrap_err();
394 parse("-0z", Some(12)).unwrap_err();
395 }
396
397 #[test]
398 fn binary_alpha_requires_zero_prefix() {
399 parse("B1", None).unwrap_err();
400 parse("b1", None).unwrap_err();
401 }
402
403 #[test]
404 fn binary_parses() {
405 let result = parse("0B1111", None);
406 assert_eq!(result.unwrap(), 15);
407 let result = parse("0b1111", None);
408 assert_eq!(result.unwrap(), 15);
409 let result = parse("-0B1111", None);
410 assert_eq!(result.unwrap(), -15);
411 let result = parse("-0b1111", None);
412 assert_eq!(result.unwrap(), -15);
413 }
414
415 #[test]
416 fn binary_with_given_2_radix_parses() {
417 let result = parse("0B1111", Some(2));
418 assert_eq!(result.unwrap(), 15);
419 let result = parse("0b1111", Some(2));
420 assert_eq!(result.unwrap(), 15);
421 let result = parse("-0B1111", Some(2));
422 assert_eq!(result.unwrap(), -15);
423 let result = parse("-0b1111", Some(2));
424 assert_eq!(result.unwrap(), -15);
425 }
426
427 #[test]
428 fn binary_with_mismatched_radix_is_err() {
429 parse("0B1111", Some(24)).unwrap_err();
430 parse("0b1111", Some(24)).unwrap_err();
431 parse("-0B1111", Some(24)).unwrap_err();
432 parse("-0b1111", Some(24)).unwrap_err();
433 }
434
435 #[test]
436 fn binary_with_digits_out_of_radix_is_err() {
437 parse("0B1111AH", None).unwrap_err();
438 parse("0b1111ah", None).unwrap_err();
439 }
440
441 #[test]
442 fn octal_alpha_requires_zero_prefix() {
443 parse("O7", None).unwrap_err();
444 parse("o7", None).unwrap_err();
445 }
446
447 #[test]
448 fn octal_parses() {
449 let result = parse("0O17", None);
450 assert_eq!(result.unwrap(), 15);
451 let result = parse("0o17", None);
452 assert_eq!(result.unwrap(), 15);
453 let result = parse("-0O17", None);
454 assert_eq!(result.unwrap(), -15);
455 let result = parse("-0o17", None);
456 assert_eq!(result.unwrap(), -15);
457 }
458
459 #[test]
460 fn octal_with_given_8_radix_parses() {
461 let result = parse("0O17", Some(8));
462 assert_eq!(result.unwrap(), 15);
463 let result = parse("0o17", Some(8));
464 assert_eq!(result.unwrap(), 15);
465 let result = parse("-0O17", Some(8));
466 assert_eq!(result.unwrap(), -15);
467 let result = parse("-0o17", Some(8));
468 assert_eq!(result.unwrap(), -15);
469 }
470
471 #[test]
472 fn octal_no_alpha_parses() {
473 let result = parse("017", None);
474 assert_eq!(result.unwrap(), 15);
475 let result = parse("-017", None);
476 assert_eq!(result.unwrap(), -15);
477 }
478
479 #[test]
480 fn octal_no_alpha_with_given_8_radix_parses() {
481 let result = parse("017", Some(8));
482 assert_eq!(result.unwrap(), 15);
483 let result = parse("-017", Some(8));
484 assert_eq!(result.unwrap(), -15);
485 }
486
487 #[test]
488 fn octal_with_mismatched_radix_is_err() {
489 parse("0O17", Some(24)).unwrap_err();
490 parse("0o17", Some(24)).unwrap_err();
491 parse("-0O17", Some(24)).unwrap_err();
492 parse("-0o17", Some(24)).unwrap_err();
493 }
494
495 #[test]
496 fn octal_with_digits_out_of_radix_is_err() {
497 parse("0O17AH", None).unwrap_err();
498 parse("0o17ah", None).unwrap_err();
499 }
500
501 #[test]
502 fn decimal_alpha_requires_zero_prefix() {
503 parse("D9", None).unwrap_err();
504 parse("d9", None).unwrap_err();
505 }
506
507 #[test]
508 fn decimal_parses() {
509 let result = parse("0D15", None);
510 assert_eq!(result.unwrap(), 15);
511 let result = parse("0d15", None);
512 assert_eq!(result.unwrap(), 15);
513 let result = parse("-0D15", None);
514 assert_eq!(result.unwrap(), -15);
515 let result = parse("-0d15", None);
516 assert_eq!(result.unwrap(), -15);
517 }
518
519 #[test]
520 fn decimal_with_given_10_radix_parses() {
521 let result = parse("0D15", Some(10));
522 assert_eq!(result.unwrap(), 15);
523 let result = parse("0d15", Some(10));
524 assert_eq!(result.unwrap(), 15);
525 let result = parse("-0D15", Some(10));
526 assert_eq!(result.unwrap(), -15);
527 let result = parse("-0d15", Some(10));
528 assert_eq!(result.unwrap(), -15);
529 }
530
531 #[test]
532 fn decimal_with_mismatched_radix_is_err() {
533 parse("0D15", Some(24)).unwrap_err();
534 parse("0d15", Some(24)).unwrap_err();
535 parse("-0D15", Some(24)).unwrap_err();
536 parse("-0d15", Some(24)).unwrap_err();
537 }
538
539 #[test]
540 fn decimal_with_digits_out_of_radix_is_err() {
541 parse("0D15AH", None).unwrap_err();
542 parse("0d15ah", None).unwrap_err();
543 }
544
545 #[test]
546 fn hex_alpha_requires_zero_prefix() {
547 parse("XF", None).unwrap_err();
548 parse("xF", None).unwrap_err();
549 parse("Xf", None).unwrap_err();
550 parse("xf", None).unwrap_err();
551 }
552
553 #[test]
554 fn hex_parses() {
555 let result = parse("0XF", None);
556 assert_eq!(result.unwrap(), 15);
557 let result = parse("0xF", None);
558 assert_eq!(result.unwrap(), 15);
559 let result = parse("-0XF", None);
560 assert_eq!(result.unwrap(), -15);
561 let result = parse("-0xF", None);
562 assert_eq!(result.unwrap(), -15);
563 let result = parse("0Xf", None);
564 assert_eq!(result.unwrap(), 15);
565 let result = parse("0xf", None);
566 assert_eq!(result.unwrap(), 15);
567 let result = parse("-0Xf", None);
568 assert_eq!(result.unwrap(), -15);
569 let result = parse("-0xf", None);
570 assert_eq!(result.unwrap(), -15);
571 }
572
573 #[test]
574 fn hex_with_given_16_radix_parses() {
575 let result = parse("0XF", Some(16));
576 assert_eq!(result.unwrap(), 15);
577 let result = parse("0xF", Some(16));
578 assert_eq!(result.unwrap(), 15);
579 let result = parse("-0XF", Some(16));
580 assert_eq!(result.unwrap(), -15);
581 let result = parse("-0xF", Some(16));
582 assert_eq!(result.unwrap(), -15);
583 let result = parse("0Xf", Some(16));
584 assert_eq!(result.unwrap(), 15);
585 let result = parse("0xf", Some(16));
586 assert_eq!(result.unwrap(), 15);
587 let result = parse("-0Xf", Some(16));
588 assert_eq!(result.unwrap(), -15);
589 let result = parse("-0xf", Some(16));
590 assert_eq!(result.unwrap(), -15);
591 }
592
593 #[test]
594 fn hex_with_mismatched_radix_is_err() {
595 parse("0XF", Some(24)).unwrap_err();
596 parse("0xF", Some(24)).unwrap_err();
597 parse("0Xf", Some(24)).unwrap_err();
598 parse("0xf", Some(24)).unwrap_err();
599 parse("-0XF", Some(24)).unwrap_err();
600 parse("-0xF", Some(24)).unwrap_err();
601 parse("-0Xf", Some(24)).unwrap_err();
602 parse("-0xf", Some(24)).unwrap_err();
603 }
604
605 #[test]
606 fn hex_with_digits_out_of_radix_is_err() {
607 parse("0XFAH", None).unwrap_err();
608 parse("0xFah", None).unwrap_err();
609 parse("0XfAH", None).unwrap_err();
610 parse("0xfah", None).unwrap_err();
611 }
612
613 #[test]
614 fn digits_out_of_radix_is_err() {
615 parse("17AH", Some(12)).unwrap_err();
616 parse("17ah", Some(12)).unwrap_err();
617 parse("17AH", None).unwrap_err();
618 parse("17ah", None).unwrap_err();
619 }
620
621 #[test]
622 fn parsing_is_case_insensitive() {
623 let result = parse("abcdefgxyz", Some(36));
630 assert_eq!(result.unwrap(), 1_047_601_316_316_923);
631 let result = parse("ABCDEFGXYZ", Some(36));
632 assert_eq!(result.unwrap(), 1_047_601_316_316_923);
633 }
634
635 #[test]
636 fn leading_underscore_is_err() {
637 parse("0x_0000001234567", None).unwrap_err();
638 parse("0_x0000001234567", None).unwrap_err();
639 parse("___0x0000001234567", None).unwrap_err();
640 }
641
642 #[test]
643 fn double_underscore_is_err() {
644 parse("0x111__11", None).unwrap_err();
645 }
646
647 #[test]
648 fn trailing_underscore_is_err() {
649 parse("0x111_11_", None).unwrap_err();
650 parse("0x00000_", None).unwrap_err();
651 }
652
653 #[test]
654 fn all_spaces_is_err() {
655 parse(" ", None).unwrap_err();
656 }
657
658 #[test]
659 fn empty_is_err() {
660 parse("", None).unwrap_err();
661 }
662
663 #[test]
664 fn more_than_one_sign_is_err() {
665 parse("++12", None).unwrap_err();
666 parse("+-12", None).unwrap_err();
667 parse("-+12", None).unwrap_err();
668 parse("--12", None).unwrap_err();
669 }
670
671 #[test]
672 fn zero_radix_is_default() {
673 let result = parse("0x111", Some(0));
680 assert_eq!(result.unwrap(), 273);
681 let result = parse("111", Some(0));
682 assert_eq!(result.unwrap(), 111);
683 }
684
685 #[test]
686 fn negative_one_radix_is_default() {
687 let result = parse("0x123f", Some(-1));
696 assert_eq!(result.unwrap(), 4671);
697 let result = parse("111", Some(-1));
698 assert_eq!(result.unwrap(), 111);
699 }
700
701 #[test]
702 fn one_radix_is_err() {
703 parse("0x123f", Some(1)).unwrap_err();
704 parse("111", Some(1)).unwrap_err();
705 }
706
707 #[test]
708 fn out_of_range_radix_is_err() {
709 parse("0x123f", Some(1200)).unwrap_err();
710 parse("123", Some(1200)).unwrap_err();
711 parse("123", Some(-1200)).unwrap_err();
712 }
713
714 #[test]
715 fn literals_with_negative_out_of_range_radix_ignore_radix() {
716 let result = parse("0x123f", Some(-1200));
717 assert_eq!(result.unwrap(), 4671);
718 }
719
720 #[test]
721 fn negative_radix_in_valid_range_is_parsed() {
722 let result = parse("111", Some(-2));
731 assert_eq!(result.unwrap(), 7);
732 let result = parse("111", Some(-10));
733 assert_eq!(result.unwrap(), 111);
734 let result = parse("111", Some(-36));
735 assert_eq!(result.unwrap(), 1333);
736 }
737
738 #[test]
739 fn all_valid_radixes() {
740 let test_cases = [
745 ("111", 2, 7),
746 ("111", 3, 13),
747 ("111", 4, 21),
748 ("111", 5, 31),
749 ("111", 6, 43),
750 ("111", 7, 57),
751 ("111", 8, 73),
752 ("111", 9, 91),
753 ("111", 10, 111),
754 ("111", 11, 133),
755 ("111", 12, 157),
756 ("111", 13, 183),
757 ("111", 14, 211),
758 ("111", 15, 241),
759 ("111", 16, 273),
760 ("111", 17, 307),
761 ("111", 18, 343),
762 ("111", 19, 381),
763 ("111", 20, 421),
764 ("111", 21, 463),
765 ("111", 22, 507),
766 ("111", 23, 553),
767 ("111", 24, 601),
768 ("111", 25, 651),
769 ("111", 26, 703),
770 ("111", 27, 757),
771 ("111", 28, 813),
772 ("111", 29, 871),
773 ("111", 30, 931),
774 ("111", 31, 993),
775 ("111", 32, 1057),
776 ("111", 33, 1123),
777 ("111", 34, 1191),
778 ("111", 35, 1261),
779 ("111", 36, 1333),
780 ("111", -2, 7),
781 ("111", -3, 13),
782 ("111", -4, 21),
783 ("111", -5, 31),
784 ("111", -6, 43),
785 ("111", -7, 57),
786 ("111", -8, 73),
787 ("111", -9, 91),
788 ("111", -10, 111),
789 ("111", -11, 133),
790 ("111", -12, 157),
791 ("111", -13, 183),
792 ("111", -14, 211),
793 ("111", -15, 241),
794 ("111", -16, 273),
795 ("111", -17, 307),
796 ("111", -18, 343),
797 ("111", -19, 381),
798 ("111", -20, 421),
799 ("111", -21, 463),
800 ("111", -22, 507),
801 ("111", -23, 553),
802 ("111", -24, 601),
803 ("111", -25, 651),
804 ("111", -26, 703),
805 ("111", -27, 757),
806 ("111", -28, 813),
807 ("111", -29, 871),
808 ("111", -30, 931),
809 ("111", -31, 993),
810 ("111", -32, 1057),
811 ("111", -33, 1123),
812 ("111", -34, 1191),
813 ("111", -35, 1261),
814 ("111", -36, 1333),
815 ];
816 for (subject, radix, output) in test_cases {
817 let result = parse(subject, Some(radix));
818 assert_eq!(
819 result.unwrap(),
820 output,
821 "Mismatched output for test case ({subject}, {radix}, {output})"
822 );
823 }
824 }
825
826 #[test]
827 fn int_max_radix_does_not_panic() {
828 parse("111", Some(i64::MAX)).unwrap_err();
829 }
830
831 #[test]
832 fn int_min_radix_does_not_panic() {
833 parse("111", Some(i64::MIN)).unwrap_err();
834 }
835
836 #[test]
837 fn decimal_zero() {
838 let result = parse("0", None);
839 assert_eq!(result.unwrap(), 0);
840 let result = parse("0", Some(2));
841 assert_eq!(result.unwrap(), 0);
842 let result = parse("0", Some(8));
843 assert_eq!(result.unwrap(), 0);
844 let result = parse("0", Some(10));
845 assert_eq!(result.unwrap(), 0);
846 let result = parse("0", Some(16));
847 assert_eq!(result.unwrap(), 0);
848 let result = parse("0", Some(36));
849 assert_eq!(result.unwrap(), 0);
850 }
851
852 #[test]
853 fn decimal_zero_whitespace() {
854 let result = parse("0 ", None);
855 assert_eq!(result.unwrap(), 0);
856 let result = parse(" 0", None);
857 assert_eq!(result.unwrap(), 0);
858 let result = parse(" 0 ", None);
859 assert_eq!(result.unwrap(), 0);
860 }
861
862 #[test]
863 fn trailing_whitespace() {
864 let result = parse("1 ", None);
865 assert_eq!(result.unwrap(), 1);
866 }
867
868 #[test]
869 fn all_ascii_whitespace_is_trimmed_from_end() {
870 let result = parse("93 ", None);
885 assert_eq!(result.unwrap(), 93);
886 let result = parse("93\n", None);
887 assert_eq!(result.unwrap(), 93);
888 let result = parse("93\t", None);
889 assert_eq!(result.unwrap(), 93);
890 let result = parse("93\u{000A}", None);
891 assert_eq!(result.unwrap(), 93);
892 let result = parse("93\u{000C}", None);
893 assert_eq!(result.unwrap(), 93);
894 let result = parse("93\u{000D}", None);
895 assert_eq!(result.unwrap(), 93);
896 }
897
898 #[test]
899 fn all_ascii_whitespace_is_trimmed_from_start() {
900 let result = parse(" 93", None);
915 assert_eq!(result.unwrap(), 93);
916 let result = parse("\n93", None);
917 assert_eq!(result.unwrap(), 93);
918 let result = parse("\t93", None);
919 assert_eq!(result.unwrap(), 93);
920 let result = parse("\u{000A}93", None);
921 assert_eq!(result.unwrap(), 93);
922 let result = parse("\u{000C}93", None);
923 assert_eq!(result.unwrap(), 93);
924 let result = parse("\u{000D}93", None);
925 assert_eq!(result.unwrap(), 93);
926 }
927
928 #[test]
929 fn inputs_with_both_leading_and_trailing_whitespace_are_parsed() {
930 let result = parse(" 93 ", None);
931 assert_eq!(result.unwrap(), 93);
932 let result = parse("\n 93 \n", None);
933 assert_eq!(result.unwrap(), 93);
934 let result = parse("\t 93 \t", None);
935 assert_eq!(result.unwrap(), 93);
936 let result = parse("\u{000A} 93 \u{000A}", None);
937 assert_eq!(result.unwrap(), 93);
938 let result = parse("\u{000C} 93 \u{000C}", None);
939 assert_eq!(result.unwrap(), 93);
940 let result = parse("\u{000D} 93 \u{000D}", None);
941 assert_eq!(result.unwrap(), 93);
942 }
943
944 #[test]
945 fn negative_radix_leading_whitespace() {
946 let result = parse(" 0123", Some(-6));
953 assert_eq!(result.unwrap(), 83);
954 let result = parse(" 0x123", Some(-6));
955 assert_eq!(result.unwrap(), 291);
956 }
957
958 #[test]
959 fn trim_vertical_tab() {
960 let result = parse(b" \x0B 27", None);
965 assert_eq!(result.unwrap(), 27);
966 }
967}