@@ -2,7 +2,7 @@ use pyo3::prelude::*;
2
2
use pyo3:: sync:: GILOnceCell ;
3
3
use pyo3:: { intern, Py , PyAny , Python } ;
4
4
5
- use num_bigint :: BigInt ;
5
+ use jiter :: { JsonErrorType , NumberInt } ;
6
6
7
7
use crate :: errors:: { ErrorTypeDefaults , ValError , ValResult } ;
8
8
@@ -68,29 +68,24 @@ fn strip_underscores(s: &str) -> Option<String> {
68
68
}
69
69
70
70
/// parse a string as an int
71
- ///
72
- /// max length of the input is 4300, see
73
- /// https://docs.python.org/3/whatsnew/3.11.html#other-cpython-implementation-changes and
74
- /// https://github.com/python/cpython/issues/95778 for more info in that length bound
75
71
pub fn str_as_int < ' py > ( input : & ( impl Input < ' py > + ?Sized ) , str : & str ) -> ValResult < EitherInt < ' py > > {
76
72
let str = str. trim ( ) ;
77
- let len = str. len ( ) ;
78
- if len > 4300 {
79
- Err ( ValError :: new ( ErrorTypeDefaults :: IntParsingSize , input) )
80
- } else if let Some ( int) = _parse_str ( input, str, len) {
81
- Ok ( int)
82
- } else if let Some ( str_stripped) = strip_decimal_zeros ( str) {
83
- if let Some ( int) = _parse_str ( input, str_stripped, len) {
84
- Ok ( int)
85
- } else {
86
- Err ( ValError :: new ( ErrorTypeDefaults :: IntParsing , input) )
73
+
74
+ // we have to call `NumberInt::try_from` directly first so we fail fast if the string is too long
75
+ match NumberInt :: try_from ( str. as_bytes ( ) ) {
76
+ Ok ( NumberInt :: Int ( i) ) => return Ok ( EitherInt :: I64 ( i) ) ,
77
+ Ok ( NumberInt :: BigInt ( i) ) => return Ok ( EitherInt :: BigInt ( i) ) ,
78
+ Err ( e) => {
79
+ if e. error_type == JsonErrorType :: NumberOutOfRange {
80
+ return Err ( ValError :: new ( ErrorTypeDefaults :: IntParsingSize , input) ) ;
81
+ }
87
82
}
83
+ }
84
+
85
+ if let Some ( str_stripped) = strip_decimal_zeros ( str) {
86
+ _parse_str ( input, str_stripped)
88
87
} else if let Some ( str_stripped) = strip_underscores ( str) {
89
- if let Some ( int) = _parse_str ( input, & str_stripped, len) {
90
- Ok ( int)
91
- } else {
92
- Err ( ValError :: new ( ErrorTypeDefaults :: IntParsing , input) )
93
- }
88
+ _parse_str ( input, & str_stripped)
94
89
} else {
95
90
Err ( ValError :: new ( ErrorTypeDefaults :: IntParsing , input) )
96
91
}
@@ -108,16 +103,18 @@ pub fn str_as_float<'py>(input: &(impl Input<'py> + ?Sized), str: &str) -> ValRe
108
103
}
109
104
110
105
/// parse a string as an int, `input` is required here to get lifetimes to match up
111
- ///
112
- fn _parse_str < ' py > ( _input : & ( impl Input < ' py > + ?Sized ) , str : & str , len : usize ) -> Option < EitherInt < ' py > > {
113
- if len < 19 {
114
- if let Ok ( i) = str. parse :: < i64 > ( ) {
115
- return Some ( EitherInt :: I64 ( i) ) ;
116
- }
117
- } else if let Ok ( i) = str. parse :: < BigInt > ( ) {
118
- return Some ( EitherInt :: BigInt ( i) ) ;
106
+ /// max length of the input is 4300 which is checked by jiter, see
107
+ /// https://docs.python.org/3/whatsnew/3.11.html#other-cpython-implementation-changes and
108
+ /// https://github.com/python/cpython/issues/95778 for more info in that length bound
109
+ fn _parse_str < ' py > ( input : & ( impl Input < ' py > + ?Sized ) , str : & str ) -> ValResult < EitherInt < ' py > > {
110
+ match NumberInt :: try_from ( str. as_bytes ( ) ) {
111
+ Ok ( jiter:: NumberInt :: Int ( i) ) => Ok ( EitherInt :: I64 ( i) ) ,
112
+ Ok ( jiter:: NumberInt :: BigInt ( i) ) => Ok ( EitherInt :: BigInt ( i) ) ,
113
+ Err ( e) => match e. error_type {
114
+ JsonErrorType :: NumberOutOfRange => Err ( ValError :: new ( ErrorTypeDefaults :: IntParsingSize , input) ) ,
115
+ _ => Err ( ValError :: new ( ErrorTypeDefaults :: IntParsing , input) ) ,
116
+ } ,
119
117
}
120
- None
121
118
}
122
119
123
120
/// we don't want to parse as f64 then call `float_as_int` as it can loose precision for large ints, therefore
0 commit comments