@@ -120,19 +120,26 @@ macro_rules! into_error {
120
120
#[ cfg( feature = "format" ) ]
121
121
macro_rules! fmt_invalid_digit {
122
122
(
123
- $value: ident, $iter: ident, $c: expr, $start_index: ident, $invalid_digit: ident, $is_end: expr
123
+ $value: ident,
124
+ $iter: ident,
125
+ $c: expr,
126
+ $start_index: ident,
127
+ $invalid_digit: ident,
128
+ $has_suffix: ident,
129
+ $is_end: expr $( , ) ?
124
130
) => { {
125
131
// NOTE: If we have non-contiguous iterators, we could have a skip character
126
132
// here at the boundary. This does not affect safety but it does affect
127
133
// correctness.
128
134
debug_assert!( $iter. is_contiguous( ) || $is_end) ;
129
135
130
- let base_suffix = NumberFormat :: <FORMAT >:: BASE_SUFFIX ;
131
- let uncased_base_suffix = NumberFormat :: <FORMAT >:: CASE_SENSITIVE_BASE_SUFFIX ;
136
+ let format = NumberFormat :: <FORMAT > { } ;
137
+ let base_suffix = format. base_suffix( ) ;
138
+ let uncased_base_suffix = format. case_sensitive_base_suffix( ) ;
132
139
// Need to check for a base suffix, if so, return a valid value.
133
140
// We can't have a base suffix at the first value (need at least
134
141
// 1 digit).
135
- if base_suffix != 0 && $iter. cursor( ) - $start_index > 1 {
142
+ if cfg! ( feature = "power-of-two" ) && base_suffix != 0 && $iter. cursor( ) - $start_index > 1 {
136
143
let is_suffix = if uncased_base_suffix {
137
144
$c == base_suffix
138
145
} else {
@@ -144,6 +151,7 @@ macro_rules! fmt_invalid_digit {
144
151
// contiguous iterators.
145
152
if is_suffix && $is_end && $iter. is_buffer_empty( ) {
146
153
// Break out of the loop, we've finished parsing.
154
+ $has_suffix = true ;
147
155
break ;
148
156
} else if !$iter. is_buffer_empty( ) {
149
157
// Haven't finished parsing, so we're going to call
@@ -165,7 +173,13 @@ macro_rules! fmt_invalid_digit {
165
173
#[ cfg( not( feature = "format" ) ) ]
166
174
macro_rules! fmt_invalid_digit {
167
175
(
168
- $value: ident, $iter: ident, $c: expr, $start_index: ident, $invalid_digit: ident, $is_end: expr
176
+ $value: ident,
177
+ $iter: ident,
178
+ $c: expr,
179
+ $start_index: ident,
180
+ $invalid_digit: ident,
181
+ $has_suffix: ident,
182
+ $is_end: expr $( , ) ?
169
183
) => { {
170
184
$invalid_digit!( $value, $iter. cursor( ) , $iter. current_count( ) ) ;
171
185
} } ;
@@ -393,6 +407,7 @@ where
393
407
/// * `add_op` - The unchecked add/sub op.
394
408
/// * `start_index` - The offset where parsing started.
395
409
/// * `invalid_digit` - Behavior when an invalid digit is found.
410
+ /// * `has_suffix` - If a base suffix was found at the end of the buffer.
396
411
/// * `is_end` - If iter corresponds to the full input.
397
412
///
398
413
/// core: <https://doc.rust-lang.org/1.81.0/src/core/num/mod.rs.html#1480>
@@ -403,15 +418,24 @@ macro_rules! parse_1digit_unchecked {
403
418
$add_op: ident,
404
419
$start_index: ident,
405
420
$invalid_digit: ident,
406
- $is_end: expr
421
+ $has_suffix: ident,
422
+ $is_end: expr $( , ) ?
407
423
) => { {
408
424
// This is a slower parsing algorithm, going 1 digit at a time, but doing it in
409
425
// an unchecked loop.
410
426
let radix = NumberFormat :: <FORMAT >:: MANTISSA_RADIX ;
411
427
while let Some ( & c) = $iter. next( ) {
412
428
let digit = match char_to_digit_const( c, radix) {
413
429
Some ( v) => v,
414
- None => fmt_invalid_digit!( $value, $iter, c, $start_index, $invalid_digit, $is_end) ,
430
+ None => fmt_invalid_digit!(
431
+ $value,
432
+ $iter,
433
+ c,
434
+ $start_index,
435
+ $invalid_digit,
436
+ $has_suffix,
437
+ $is_end,
438
+ ) ,
415
439
} ;
416
440
// multiply first since compilers are good at optimizing things out and will do
417
441
// a fused mul/add We must do this after getting the digit for
@@ -431,6 +455,7 @@ macro_rules! parse_1digit_unchecked {
431
455
/// * `add_op` - The checked add/sub op.
432
456
/// * `start_index` - The offset where parsing started.
433
457
/// * `invalid_digit` - Behavior when an invalid digit is found.
458
+ /// * `has_suffix` - If a base suffix was found at the end of the buffer.
434
459
/// * `overflow` - If the error is overflow or underflow.
435
460
///
436
461
/// core: <https://doc.rust-lang.org/1.81.0/src/core/num/mod.rs.html#1505>
@@ -441,15 +466,24 @@ macro_rules! parse_1digit_checked {
441
466
$add_op: ident,
442
467
$start_index: ident,
443
468
$invalid_digit: ident,
444
- $overflow: ident
469
+ $has_suffix: ident,
470
+ $overflow: ident $( , ) ?
445
471
) => { {
446
472
// This is a slower parsing algorithm, going 1 digit at a time, but doing it in
447
473
// an unchecked loop.
448
474
let radix = NumberFormat :: <FORMAT >:: MANTISSA_RADIX ;
449
475
while let Some ( & c) = $iter. next( ) {
450
476
let digit = match char_to_digit_const( c, radix) {
451
477
Some ( v) => v,
452
- None => fmt_invalid_digit!( $value, $iter, c, $start_index, $invalid_digit, true ) ,
478
+ None => fmt_invalid_digit!(
479
+ $value,
480
+ $iter,
481
+ c,
482
+ $start_index,
483
+ $invalid_digit,
484
+ $has_suffix,
485
+ true ,
486
+ ) ,
453
487
} ;
454
488
// multiply first since compilers are good at optimizing things out and will do
455
489
// a fused mul/add
@@ -477,6 +511,7 @@ macro_rules! parse_1digit_checked {
477
511
/// * `start_index` - The offset where parsing started.
478
512
/// * `invalid_digit` - Behavior when an invalid digit is found.
479
513
/// * `no_multi_digit` - If to disable multi-digit optimizations.
514
+ /// * `has_suffix` - If a base suffix was found at the end of the buffer.
480
515
/// * `is_end` - If iter corresponds to the full input.
481
516
macro_rules! parse_digits_unchecked {
482
517
(
@@ -486,7 +521,8 @@ macro_rules! parse_digits_unchecked {
486
521
$start_index: ident,
487
522
$invalid_digit: ident,
488
523
$no_multi_digit: expr,
489
- $is_end: expr
524
+ $has_suffix: ident,
525
+ $is_end: expr $( , ) ?
490
526
) => { {
491
527
let can_multi = can_try_parse_multidigits:: <_, FORMAT >( & $iter) ;
492
528
let use_multi = can_multi && !$no_multi_digit;
@@ -510,7 +546,15 @@ macro_rules! parse_digits_unchecked {
510
546
$value = $value. wrapping_mul( radix4) . $add_op( value) ;
511
547
}
512
548
}
513
- parse_1digit_unchecked!( $value, $iter, $add_op, $start_index, $invalid_digit, $is_end)
549
+ parse_1digit_unchecked!(
550
+ $value,
551
+ $iter,
552
+ $add_op,
553
+ $start_index,
554
+ $invalid_digit,
555
+ $has_suffix,
556
+ $is_end
557
+ )
514
558
} } ;
515
559
}
516
560
@@ -528,6 +572,7 @@ macro_rules! parse_digits_unchecked {
528
572
/// * `invalid_digit` - Behavior when an invalid digit is found.
529
573
/// * `overflow` - If the error is overflow or underflow.
530
574
/// * `no_multi_digit` - If to disable multi-digit optimizations.
575
+ /// * `has_suffix` - If a base suffix was found at the end of the buffer.
531
576
/// * `overflow_digits` - The number of digits before we need to consider
532
577
/// checked ops.
533
578
macro_rules! parse_digits_checked {
@@ -540,7 +585,8 @@ macro_rules! parse_digits_checked {
540
585
$invalid_digit: ident,
541
586
$overflow: ident,
542
587
$no_multi_digit: expr,
543
- $overflow_digits: expr
588
+ $has_suffix: ident,
589
+ $overflow_digits: expr $( , ) ?
544
590
) => { {
545
591
// Can use the unchecked for the `max_digits` here. If we
546
592
// have a non-contiguous iterator, we could have a case like
@@ -557,13 +603,22 @@ macro_rules! parse_digits_checked {
557
603
$start_index,
558
604
$invalid_digit,
559
605
$no_multi_digit,
606
+ $has_suffix,
560
607
false
561
608
) ;
562
609
}
563
610
}
564
611
565
612
// NOTE: all our multi-digit optimizations have been done here: skip this
566
- parse_1digit_checked!( $value, $iter, $add_op, $start_index, $invalid_digit, $overflow)
613
+ parse_1digit_checked!(
614
+ $value,
615
+ $iter,
616
+ $add_op,
617
+ $start_index,
618
+ $invalid_digit,
619
+ $has_suffix,
620
+ $overflow
621
+ )
567
622
} } ;
568
623
}
569
624
@@ -650,6 +705,9 @@ macro_rules! algorithm {
650
705
}
651
706
}
652
707
}
708
+ if cfg!( all( feature = "format" , feature = "power-of-two" ) ) && format. required_base_prefix( ) && !is_prefix {
709
+ return Err ( Error :: MissingBasePrefix ( iter. cursor( ) ) ) ;
710
+ }
653
711
654
712
// If we have a format that doesn't accept leading zeros,
655
713
// check if the next value is invalid. It's invalid if the
@@ -684,14 +742,60 @@ macro_rules! algorithm {
684
742
// culminates in **way** slower performance overall for simple
685
743
// integers, and no improvement for large integers.
686
744
let mut value = T :: ZERO ;
745
+ #[ allow( unused_mut) ]
746
+ let mut has_suffix = false ;
687
747
if cannot_overflow && is_negative {
688
- parse_digits_unchecked!( value, iter, wrapping_sub, start_index, $invalid_digit, $no_multi_digit, true ) ;
748
+ parse_digits_unchecked!(
749
+ value,
750
+ iter,
751
+ wrapping_sub,
752
+ start_index,
753
+ $invalid_digit,
754
+ $no_multi_digit,
755
+ has_suffix,
756
+ true ,
757
+ ) ;
689
758
} if cannot_overflow {
690
- parse_digits_unchecked!( value, iter, wrapping_add, start_index, $invalid_digit, $no_multi_digit, true ) ;
759
+ parse_digits_unchecked!(
760
+ value,
761
+ iter,
762
+ wrapping_add,
763
+ start_index,
764
+ $invalid_digit,
765
+ $no_multi_digit,
766
+ has_suffix,
767
+ true ,
768
+ ) ;
691
769
} else if is_negative {
692
- parse_digits_checked!( value, iter, checked_sub, wrapping_sub, start_index, $invalid_digit, Underflow , $no_multi_digit, overflow_digits) ;
770
+ parse_digits_checked!(
771
+ value,
772
+ iter,
773
+ checked_sub,
774
+ wrapping_sub,
775
+ start_index,
776
+ $invalid_digit,
777
+ Underflow ,
778
+ $no_multi_digit,
779
+ has_suffix,
780
+ overflow_digits,
781
+ ) ;
693
782
} else {
694
- parse_digits_checked!( value, iter, checked_add, wrapping_add, start_index, $invalid_digit, Overflow , $no_multi_digit, overflow_digits) ;
783
+ parse_digits_checked!(
784
+ value,
785
+ iter,
786
+ checked_add,
787
+ wrapping_add,
788
+ start_index,
789
+ $invalid_digit,
790
+ Overflow ,
791
+ $no_multi_digit,
792
+ has_suffix,
793
+ overflow_digits,
794
+ ) ;
795
+ }
796
+
797
+ if cfg!( all( feature = "format" , feature = "power-of-two" ) ) && format. required_base_suffix( ) && !has_suffix {
798
+ return Err ( Error :: MissingBaseSuffix ( iter. cursor( ) ) ) ;
695
799
}
696
800
697
801
$into_ok!( value, iter. buffer_length( ) , iter. current_count( ) )
0 commit comments