Skip to content

Commit 751d15b

Browse files
committed
feat(serde): optimize integer parsing in deserializer
1 parent 6eff8a7 commit 751d15b

2 files changed

Lines changed: 182 additions & 1 deletion

File tree

src/serde/de.rs

Lines changed: 170 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,164 @@ impl<'de> Deserializer<'de> {
154154
Err(Error::ExpectedString)
155155
}
156156
}
157+
158+
fn parse_integer_float(&self) -> Result<f64> {
159+
let current = self.get_current();
160+
if !current.is_float() {
161+
return Err(Error::ExpectedFloat);
162+
}
163+
164+
let value = current.to_float()?;
165+
166+
if !value.is_finite() || value.fract() != 0.0 {
167+
return Err(Error::ExpectedInteger);
168+
}
169+
170+
Ok(value)
171+
}
172+
173+
fn parse_signed_integer(&self) -> Result<i64> {
174+
let current = self.get_current();
175+
176+
if current.is_int() {
177+
return Ok(i64::from(current.to_int()?));
178+
}
179+
180+
if current.is_float() {
181+
let value = self.parse_integer_float()?;
182+
if value < i64::MIN as f64 || value > i64::MAX as f64 {
183+
return Err(crate::ValueError::OutOfRange.into());
184+
}
185+
return Ok(value as i64);
186+
}
187+
188+
#[cfg(feature = "bigint")]
189+
if current.is_bigint() {
190+
return current.to_bigint()?.as_i64().ok_or(Error::BigIntOverflow);
191+
}
192+
193+
Err(Error::ExpectedInteger)
194+
}
195+
196+
fn parse_unsigned_integer(&self) -> Result<u64> {
197+
let current = self.get_current();
198+
199+
if current.is_int() {
200+
let value = current.to_int()?;
201+
if value < 0 {
202+
return Err(crate::ValueError::OutOfRange.into());
203+
}
204+
return Ok(value as u64);
205+
}
206+
207+
if current.is_float() {
208+
let value = self.parse_integer_float()?;
209+
if value < 0.0 || value > u64::MAX as f64 {
210+
return Err(crate::ValueError::OutOfRange.into());
211+
}
212+
return Ok(value as u64);
213+
}
214+
215+
#[cfg(feature = "bigint")]
216+
if current.is_bigint() {
217+
use num_traits::ToPrimitive;
218+
219+
return current
220+
.to_bigint()?
221+
.into_bigint()
222+
.to_u64()
223+
.ok_or(Error::BigIntOverflow);
224+
}
225+
226+
Err(Error::ExpectedInteger)
227+
}
228+
229+
#[cfg(feature = "bigint")]
230+
fn parse_signed_integer_128(&self) -> Result<i128> {
231+
let current = self.get_current();
232+
233+
if current.is_bigint() {
234+
use num_traits::ToPrimitive;
235+
236+
return current
237+
.to_bigint()?
238+
.into_bigint()
239+
.to_i128()
240+
.ok_or(Error::BigIntOverflow);
241+
}
242+
243+
if current.is_float() {
244+
let value = self.parse_integer_float()?;
245+
if value < i128::MIN as f64 || value > i128::MAX as f64 {
246+
return Err(crate::ValueError::OutOfRange.into());
247+
}
248+
return Ok(value as i128);
249+
}
250+
251+
self.parse_signed_integer().map(i128::from)
252+
}
253+
254+
#[cfg(not(feature = "bigint"))]
255+
fn parse_signed_integer_128(&self) -> Result<i128> {
256+
if self.get_current().is_float() {
257+
let value = self.parse_integer_float()?;
258+
if value < i128::MIN as f64 || value > i128::MAX as f64 {
259+
return Err(crate::ValueError::OutOfRange.into());
260+
}
261+
return Ok(value as i128);
262+
}
263+
264+
self.parse_signed_integer().map(i128::from)
265+
}
266+
267+
#[cfg(feature = "bigint")]
268+
fn parse_unsigned_integer_128(&self) -> Result<u128> {
269+
let current = self.get_current();
270+
271+
if current.is_bigint() {
272+
use num_traits::ToPrimitive;
273+
274+
return current
275+
.to_bigint()?
276+
.into_bigint()
277+
.to_u128()
278+
.ok_or(Error::BigIntOverflow);
279+
}
280+
281+
if current.is_float() {
282+
let value = self.parse_integer_float()?;
283+
if value < 0.0 || value > u128::MAX as f64 {
284+
return Err(crate::ValueError::OutOfRange.into());
285+
}
286+
return Ok(value as u128);
287+
}
288+
289+
self.parse_unsigned_integer().map(u128::from)
290+
}
291+
292+
#[cfg(not(feature = "bigint"))]
293+
fn parse_unsigned_integer_128(&self) -> Result<u128> {
294+
if self.get_current().is_float() {
295+
let value = self.parse_integer_float()?;
296+
if value < 0.0 || value > u128::MAX as f64 {
297+
return Err(crate::ValueError::OutOfRange.into());
298+
}
299+
return Ok(value as u128);
300+
}
301+
302+
self.parse_unsigned_integer().map(u128::from)
303+
}
304+
}
305+
306+
macro_rules! deserialize_integer {
307+
($name:ident, $visit:ident, $helper:ident) => {
308+
fn $name<V>(self, visitor: V) -> std::result::Result<V::Value, Self::Error>
309+
where
310+
V: Visitor<'de>,
311+
{
312+
visitor.$visit(self.$helper()?)
313+
}
314+
};
157315
}
158316

159317
impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
@@ -219,12 +377,23 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
219377

220378
forward_to_deserialize_any! {
221379
bool
222-
i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64
380+
f32 f64
223381
string char
224382
unit
225383
identifier ignored_any
226384
}
227385

386+
deserialize_integer!(deserialize_i8, visit_i64, parse_signed_integer);
387+
deserialize_integer!(deserialize_i16, visit_i64, parse_signed_integer);
388+
deserialize_integer!(deserialize_i32, visit_i64, parse_signed_integer);
389+
deserialize_integer!(deserialize_i64, visit_i64, parse_signed_integer);
390+
deserialize_integer!(deserialize_i128, visit_i128, parse_signed_integer_128);
391+
deserialize_integer!(deserialize_u8, visit_u64, parse_unsigned_integer);
392+
deserialize_integer!(deserialize_u16, visit_u64, parse_unsigned_integer);
393+
deserialize_integer!(deserialize_u32, visit_u64, parse_unsigned_integer);
394+
deserialize_integer!(deserialize_u64, visit_u64, parse_unsigned_integer);
395+
deserialize_integer!(deserialize_u128, visit_u128, parse_unsigned_integer_128);
396+
228397
fn deserialize_str<V>(self, visitor: V) -> std::result::Result<V::Value, Self::Error>
229398
where
230399
V: Visitor<'de>,

tests/serde.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,18 @@ fn serde_de_float() {
282282
assert_eq!(parse_from_js::<f64>(value), 3.14159265);
283283
}
284284

285+
#[test]
286+
fn serde_de_float_with_integer_value_to_u32() {
287+
let value = json!(1450.0);
288+
assert_eq!(parse_from_js::<u32>(value), 1450);
289+
}
290+
291+
#[test]
292+
fn serde_de_float_with_integer_value_to_i32() {
293+
let value = json!(-1234.0);
294+
assert_eq!(parse_from_js::<i32>(value), -1234);
295+
}
296+
285297
#[test]
286298
fn serde_de_option_none() {
287299
let value = json!(None::<()>);

0 commit comments

Comments
 (0)