@@ -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
21472131fn 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
22042170fn 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
22612204fn cast_string_to_decimal (
0 commit comments