in arrow-cast/src/parse.rs [732:850]
fn parse_e_notation<T: DecimalType>(
s: &str,
mut digits: u16,
mut fractionals: i16,
mut result: T::Native,
index: usize,
precision: u16,
scale: i16,
) -> Result<T::Native, ArrowError> {
let mut exp: i16 = 0;
let base = T::Native::usize_as(10);
let mut exp_start: bool = false;
// e has a plus sign
let mut pos_shift_direction: bool = true;
// skip to point or exponent index
let mut bs;
if fractionals > 0 {
// it's a fraction, so the point index needs to be skipped, so +1
bs = s.as_bytes().iter().skip(index + fractionals as usize + 1);
} else {
// it's actually an integer that is already written into the result, so let's skip on to e
bs = s.as_bytes().iter().skip(index);
}
while let Some(b) = bs.next() {
match b {
b'0'..=b'9' => {
result = result.mul_wrapping(base);
result = result.add_wrapping(T::Native::usize_as((b - b'0') as usize));
if fractionals > 0 {
fractionals += 1;
}
digits += 1;
}
&b'e' | &b'E' => {
exp_start = true;
}
_ => {
return Err(ArrowError::ParseError(format!(
"can't parse the string value {s} to decimal"
)));
}
};
if exp_start {
pos_shift_direction = match bs.next() {
Some(&b'-') => false,
Some(&b'+') => true,
Some(b) => {
if !b.is_ascii_digit() {
return Err(ArrowError::ParseError(format!(
"can't parse the string value {s} to decimal"
)));
}
exp *= 10;
exp += (b - b'0') as i16;
true
}
None => {
return Err(ArrowError::ParseError(format!(
"can't parse the string value {s} to decimal"
)))
}
};
for b in bs.by_ref() {
if !b.is_ascii_digit() {
return Err(ArrowError::ParseError(format!(
"can't parse the string value {s} to decimal"
)));
}
exp *= 10;
exp += (b - b'0') as i16;
}
}
}
if digits == 0 && fractionals == 0 && exp == 0 {
return Err(ArrowError::ParseError(format!(
"can't parse the string value {s} to decimal"
)));
}
if !pos_shift_direction {
// exponent has a large negative sign
// 1.12345e-30 => 0.0{29}12345, scale = 5
if exp - (digits as i16 + scale) > 0 {
return Ok(T::Native::usize_as(0));
}
exp *= -1;
}
// point offset
exp = fractionals - exp;
// We have zeros on the left, we need to count them
if !pos_shift_direction && exp > digits as i16 {
digits = exp as u16;
}
// Number of numbers to be removed or added
exp = scale - exp;
if (digits as i16 + exp) as u16 > precision {
return Err(ArrowError::ParseError(format!(
"parse decimal overflow ({s})"
)));
}
if exp < 0 {
result = result.div_wrapping(base.pow_wrapping(-exp as _));
} else {
result = result.mul_wrapping(base.pow_wrapping(exp as _));
}
Ok(result)
}