in arrow-cast/src/parse.rs [1162:1215]
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.split_once('.') {
Some((integer, frac))
if frac.len() <= INTERVAL_PRECISION as usize
&& !frac.is_empty()
&& !frac.starts_with('-') =>
{
// integer will be "" for values like ".5"
// and "-" for values like "-.5"
let explicit_neg = integer.starts_with('-');
let integer = if integer.is_empty() || integer == "-" {
Ok(0)
} else {
integer.parse::<i64>().map_err(|_| {
ArrowError::ParseError(format!("Failed to parse {s} as interval amount"))
})
}?;
let frac_unscaled = frac.parse::<i64>().map_err(|_| {
ArrowError::ParseError(format!("Failed to parse {s} as interval amount"))
})?;
// scale fractional part by interval precision
let frac = frac_unscaled * 10_i64.pow(INTERVAL_PRECISION - frac.len() as u32);
// propagate the sign of the integer part to the fractional part
let frac = if integer < 0 || explicit_neg {
-frac
} else {
frac
};
let result = Self { integer, frac };
Ok(result)
}
Some((_, frac)) if frac.starts_with('-') => Err(ArrowError::ParseError(format!(
"Failed to parse {s} as interval amount"
))),
Some((_, frac)) if frac.len() > INTERVAL_PRECISION as usize => {
Err(ArrowError::ParseError(format!(
"{s} exceeds the precision available for interval amount"
)))
}
Some(_) | None => {
let integer = s.parse::<i64>().map_err(|_| {
ArrowError::ParseError(format!("Failed to parse {s} as interval amount"))
})?;
let result = Self { integer, frac: 0 };
Ok(result)
}
}
}