Skip to content

Commit 37b90fb

Browse files
committed
more cleanup
1 parent e28d52a commit 37b90fb

1 file changed

Lines changed: 34 additions & 91 deletions

File tree

  • native/spark-expr/src/conversion_funcs

native/spark-expr/src/conversion_funcs/cast.rs

Lines changed: 34 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -2057,24 +2057,23 @@ fn parse_string_to_i16_try(str: &str) -> SparkResult<Option<i16>> {
20572057
}
20582058
}
20592059

2060-
// Parses sign and returns (is_negative, start_idx after sign)
2061-
// Returns None if invalid (e.g., just "+" or "-")
2062-
fn parse_sign(trimmed_bytes: &[u8]) -> Option<(bool, usize)> {
2063-
let len = trimmed_bytes.len();
2064-
if len == 0 {
2065-
return None;
2060+
/// Parses sign and returns (is_negative, remaining_bytes after sign)
2061+
/// Returns None if invalid (empty input, or just "+" or "-")
2062+
fn parse_sign(bytes: &[u8]) -> Option<(bool, &[u8])> {
2063+
let (&first, rest) = bytes.split_first()?;
2064+
match first {
2065+
b'-' if !rest.is_empty() => Some((true, rest)),
2066+
b'+' if !rest.is_empty() => Some((false, rest)),
2067+
_ => Some((false, bytes)),
20662068
}
2069+
}
20672070

2068-
let first_char = trimmed_bytes[0];
2069-
let negative = first_char == b'-';
2070-
2071-
if negative || first_char == b'+' {
2072-
if len == 1 {
2073-
return None;
2074-
}
2075-
Some((negative, 1))
2071+
/// Finalizes the result by applying the sign. Returns None if overflow would occur.
2072+
fn finalize_int_result<T: Integer + CheckedNeg + Copy>(result: T, negative: bool) -> Option<T> {
2073+
if negative {
2074+
Some(result)
20762075
} else {
2077-
Some((false, 0))
2076+
result.checked_neg().filter(|&n| n >= T::zero())
20782077
}
20792078
}
20802079

@@ -2087,11 +2086,7 @@ fn do_parse_string_to_int_legacy<T: Integer + CheckedSub + CheckedNeg + From<u8>
20872086
) -> SparkResult<Option<T>> {
20882087
let trimmed_bytes = str.as_bytes().trim_ascii();
20892088

2090-
if trimmed_bytes.is_empty() {
2091-
return Ok(None);
2092-
}
2093-
2094-
let (negative, idx) = match parse_sign(trimmed_bytes) {
2089+
let (negative, digits) = match parse_sign(trimmed_bytes) {
20952090
Some(result) => result,
20962091
None => return Ok(None),
20972092
};
@@ -2100,7 +2095,7 @@ fn do_parse_string_to_int_legacy<T: Integer + CheckedSub + CheckedNeg + From<u8>
21002095
let radix = T::from(10_u8);
21012096
let stop_value = min_value / radix;
21022097

2103-
let mut iter = trimmed_bytes[idx..].iter();
2098+
let mut iter = digits.iter();
21042099

21052100
// Parse integer portion until '.' or end
21062101
for &ch in iter.by_ref() {
@@ -2130,75 +2125,46 @@ fn do_parse_string_to_int_legacy<T: Integer + CheckedSub + CheckedNeg + From<u8>
21302125
}
21312126
}
21322127

2133-
if !negative {
2134-
if let Some(neg) = result.checked_neg() {
2135-
if neg < T::zero() {
2136-
return Ok(None);
2137-
}
2138-
result = neg;
2139-
} else {
2140-
return Ok(None);
2141-
}
2142-
}
2143-
2144-
Ok(Some(result))
2128+
Ok(finalize_int_result(result, negative))
21452129
}
21462130

21472131
fn do_parse_string_to_int_ansi<T: Integer + CheckedSub + CheckedNeg + From<u8> + Copy>(
21482132
str: &str,
21492133
type_name: &str,
21502134
min_value: T,
21512135
) -> SparkResult<Option<T>> {
2152-
let trimmed_bytes = str.as_bytes().trim_ascii();
2136+
let error = || Err(invalid_value(str, "STRING", type_name));
21532137

2154-
if trimmed_bytes.is_empty() {
2155-
return Err(invalid_value(str, "STRING", type_name));
2156-
}
2138+
let trimmed_bytes = str.as_bytes().trim_ascii();
21572139

2158-
let (negative, idx) = match parse_sign(trimmed_bytes) {
2140+
let (negative, digits) = match parse_sign(trimmed_bytes) {
21592141
Some(result) => result,
2160-
None => return Err(invalid_value(str, "STRING", type_name)),
2142+
None => return error(),
21612143
};
21622144

21632145
let mut result: T = T::zero();
2164-
21652146
let radix = T::from(10_u8);
21662147
let stop_value = min_value / radix;
21672148

2168-
for &ch in &trimmed_bytes[idx..] {
2169-
if ch == b'.' {
2170-
return Err(invalid_value(str, "STRING", type_name));
2171-
}
2172-
2173-
if !ch.is_ascii_digit() {
2174-
return Err(invalid_value(str, "STRING", type_name));
2149+
for &ch in digits {
2150+
if ch == b'.' || !ch.is_ascii_digit() {
2151+
return error();
21752152
}
21762153

21772154
if result < stop_value {
2178-
return Err(invalid_value(str, "STRING", type_name));
2155+
return error();
21792156
}
21802157
let v = result * radix;
21812158
let digit: T = T::from(ch - b'0');
21822159
match v.checked_sub(&digit) {
21832160
Some(x) if x <= T::zero() => result = x,
2184-
_ => {
2185-
return Err(invalid_value(str, "STRING", type_name));
2186-
}
2187-
}
2188-
}
2189-
2190-
if !negative {
2191-
if let Some(neg) = result.checked_neg() {
2192-
if neg < T::zero() {
2193-
return Err(invalid_value(str, "STRING", type_name));
2194-
}
2195-
result = neg;
2196-
} else {
2197-
return Err(invalid_value(str, "STRING", type_name));
2161+
_ => return error(),
21982162
}
21992163
}
22002164

2201-
Ok(Some(result))
2165+
finalize_int_result(result, negative)
2166+
.map(Some)
2167+
.ok_or_else(|| invalid_value(str, "STRING", type_name))
22022168
}
22032169

22042170
fn do_parse_string_to_int_try<T: Integer + CheckedSub + CheckedNeg + From<u8> + Copy>(
@@ -2207,27 +2173,17 @@ fn do_parse_string_to_int_try<T: Integer + CheckedSub + CheckedNeg + From<u8> +
22072173
) -> SparkResult<Option<T>> {
22082174
let trimmed_bytes = str.as_bytes().trim_ascii();
22092175

2210-
if trimmed_bytes.is_empty() {
2211-
return Ok(None);
2212-
}
2213-
2214-
let (negative, idx) = match parse_sign(trimmed_bytes) {
2176+
let (negative, digits) = match parse_sign(trimmed_bytes) {
22152177
Some(result) => result,
22162178
None => return Ok(None),
22172179
};
22182180

22192181
let mut result: T = T::zero();
2220-
22212182
let radix = T::from(10_u8);
22222183
let stop_value = min_value / radix;
22232184

2224-
// we don't have to go beyond decimal point in try eval mode - early return NULL
2225-
for &ch in &trimmed_bytes[idx..] {
2226-
if ch == b'.' {
2227-
return Ok(None);
2228-
}
2229-
2230-
if !ch.is_ascii_digit() {
2185+
for &ch in digits {
2186+
if ch == b'.' || !ch.is_ascii_digit() {
22312187
return Ok(None);
22322188
}
22332189

@@ -2238,24 +2194,11 @@ fn do_parse_string_to_int_try<T: Integer + CheckedSub + CheckedNeg + From<u8> +
22382194
let digit: T = T::from(ch - b'0');
22392195
match v.checked_sub(&digit) {
22402196
Some(x) if x <= T::zero() => result = x,
2241-
_ => {
2242-
return Ok(None);
2243-
}
2244-
}
2245-
}
2246-
2247-
if !negative {
2248-
if let Some(neg) = result.checked_neg() {
2249-
if neg < T::zero() {
2250-
return Ok(None);
2251-
}
2252-
result = neg;
2253-
} else {
2254-
return Ok(None);
2197+
_ => return Ok(None),
22552198
}
22562199
}
22572200

2258-
Ok(Some(result))
2201+
Ok(finalize_int_result(result, negative))
22592202
}
22602203

22612204
fn cast_string_to_decimal(

0 commit comments

Comments
 (0)