Skip to content

Commit 3dbfe0d

Browse files
committed
fix: extend test cases
1 parent de78c27 commit 3dbfe0d

File tree

1 file changed

+53
-69
lines changed

1 file changed

+53
-69
lines changed

arrow-cast/src/parse.rs

Lines changed: 53 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -741,72 +741,53 @@ fn parse_e_notation<T: DecimalType>(
741741
let mut exp: i16 = 0;
742742
let base = T::Native::usize_as(10);
743743

744-
let mut exp_start: bool = false;
745744
// e has a plus sign
746745
let mut pos_shift_direction: bool = true;
747746

748-
// skip to point or exponent index
749-
let mut bs;
750-
if fractionals > 0 {
751-
// it's a fraction, so the point index needs to be skipped, so +1
752-
bs = s.as_bytes().iter().skip(index + fractionals as usize + 1);
753-
} else {
754-
// it's actually an integer that is already written into the result, so let's skip on to e
755-
bs = s.as_bytes().iter().skip(index);
756-
}
747+
// skip to the exponent index directly or just after any processed fractionals
748+
let mut bs = s.as_bytes().iter().skip(index + fractionals as usize);
757749

758-
while let Some(b) = bs.next() {
750+
// complete parsing of any unprocessed fractionals up to the exponent
751+
for b in bs.by_ref() {
759752
match b {
760753
b'0'..=b'9' => {
761754
result = result.mul_wrapping(base);
762755
result = result.add_wrapping(T::Native::usize_as((b - b'0') as usize));
763-
if fractionals > 0 {
764-
fractionals += 1;
765-
}
756+
fractionals += 1;
766757
digits += 1;
767758
}
768-
&b'e' | &b'E' => {
769-
exp_start = true;
759+
b'e' | b'E' => {
760+
break;
770761
}
771762
_ => {
772763
return Err(ArrowError::ParseError(format!(
773764
"can't parse the string value {s} to decimal"
774765
)));
775766
}
776767
};
768+
}
777769

778-
if exp_start {
779-
pos_shift_direction = match bs.next() {
780-
Some(&b'-') => false,
781-
Some(&b'+') => true,
782-
Some(b) => {
783-
if !b.is_ascii_digit() {
784-
return Err(ArrowError::ParseError(format!(
785-
"can't parse the string value {s} to decimal"
786-
)));
787-
}
788-
789-
exp *= 10;
790-
exp += (b - b'0') as i16;
791-
792-
true
793-
}
794-
None => {
795-
return Err(ArrowError::ParseError(format!(
796-
"can't parse the string value {s} to decimal"
797-
)));
798-
}
799-
};
800-
801-
for b in bs.by_ref() {
802-
if !b.is_ascii_digit() {
803-
return Err(ArrowError::ParseError(format!(
804-
"can't parse the string value {s} to decimal"
805-
)));
806-
}
770+
// parse the exponent itself
771+
let mut signed = false;
772+
for b in bs {
773+
match b {
774+
b'-' if !signed => {
775+
pos_shift_direction = false;
776+
signed = true;
777+
}
778+
b'+' if !signed => {
779+
pos_shift_direction = true;
780+
signed = true;
781+
}
782+
b if b.is_ascii_digit() => {
807783
exp *= 10;
808784
exp += (b - b'0') as i16;
809785
}
786+
_ => {
787+
return Err(ArrowError::ParseError(format!(
788+
"can't parse the string value {s} to decimal"
789+
)));
790+
}
810791
}
811792
}
812793

@@ -903,7 +884,7 @@ pub fn parse_decimal<T: DecimalType>(
903884
digits as u16,
904885
fractionals as i16,
905886
result,
906-
point_index,
887+
point_index + 1,
907888
precision as u16,
908889
scale as i16,
909890
)?;
@@ -916,7 +897,7 @@ pub fn parse_decimal<T: DecimalType>(
916897
"can't parse the string value {s} to decimal"
917898
)));
918899
}
919-
if fractionals == scale && scale != 0 {
900+
if fractionals == scale {
920901
// We have processed all the digits that we need. All that
921902
// is left is to validate that the rest of the string contains
922903
// valid digits.
@@ -933,7 +914,7 @@ pub fn parse_decimal<T: DecimalType>(
933914
}
934915

935916
// Fail on "."
936-
if digits == 0 {
917+
if digits == 0 && scale != 0 {
937918
return Err(ArrowError::ParseError(format!(
938919
"can't parse the string value {s} to decimal"
939920
)));
@@ -963,14 +944,6 @@ pub fn parse_decimal<T: DecimalType>(
963944
}
964945

965946
if !is_e_notation {
966-
if scale == 0 && fractionals > 0 {
967-
// The input string contained some fractional digits after the decimal point despite
968-
// the scale being zero. Eject all the fractional digits from the number.
969-
result = result.div_wrapping(base.pow_wrapping(fractionals as _));
970-
digits -= fractionals as u8;
971-
fractionals = 0;
972-
}
973-
974947
if fractionals < scale {
975948
let exp = scale - fractionals;
976949
if exp as u8 + digits > precision {
@@ -2763,20 +2736,31 @@ mod tests {
27632736
}
27642737

27652738
let zero_scale_tests = [
2766-
("0.123", 0),
2767-
("1.0", 1),
2768-
("1.2", 1),
2769-
("1.00", 1),
2770-
("1.23", 1),
2771-
("1.000", 1),
2772-
("1.123", 1),
2773-
("123.0", 123),
2774-
("123.4", 123),
2775-
("123.00", 123),
2776-
("123.45", 123),
2739+
("0.123", 0, 3),
2740+
("1.0", 1, 3),
2741+
("1.2", 1, 3),
2742+
("1.00", 1, 3),
2743+
("1.23", 1, 3),
2744+
("1.000", 1, 3),
2745+
("1.123", 1, 3),
2746+
("123.0", 123, 3),
2747+
("123.4", 123, 3),
2748+
("123.00", 123, 3),
2749+
("123.45", 123, 3),
2750+
("123.000000000000000000004", 123, 3),
2751+
("0.123e2", 12, 3),
2752+
("0.123e4", 1230, 10),
2753+
("1.23e4", 12300, 10),
2754+
("12.3e4", 123000, 10),
2755+
("123e4", 1230000, 10),
2756+
(
2757+
"20000000000000000000000000000000000002.0",
2758+
20000000000000000000000000000000000002,
2759+
38,
2760+
),
27772761
];
2778-
for (s, i) in zero_scale_tests {
2779-
let result_128 = parse_decimal::<Decimal128Type>(s, 3, 0).unwrap();
2762+
for (s, i, precision) in zero_scale_tests {
2763+
let result_128 = parse_decimal::<Decimal128Type>(s, precision, 0).unwrap();
27802764
assert_eq!(i, result_128);
27812765
}
27822766
}

0 commit comments

Comments
 (0)