Skip to content

Commit 0c4a7f8

Browse files
authored
Merge pull request #1037 from dtolnay/numkey
Insert check for whitespace surrounding numeric map key deserializing from Value
2 parents 51b1bd0 + 9f4c4af commit 0c4a7f8

File tree

3 files changed

+125
-95
lines changed

3 files changed

+125
-95
lines changed

src/de.rs

+84-75
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ impl<'de, R: Read<'de>> Deserializer<R> {
209209
self.disable_recursion_limit = true;
210210
}
211211

212-
fn peek(&mut self) -> Result<Option<u8>> {
212+
pub(crate) fn peek(&mut self) -> Result<Option<u8>> {
213213
self.read.peek()
214214
}
215215

@@ -309,9 +309,9 @@ impl<'de, R: Read<'de>> Deserializer<R> {
309309
self.fix_position(err)
310310
}
311311

312-
fn deserialize_number<V>(&mut self, visitor: V) -> Result<V::Value>
312+
pub(crate) fn deserialize_number<'any, V>(&mut self, visitor: V) -> Result<V::Value>
313313
where
314-
V: de::Visitor<'de>,
314+
V: de::Visitor<'any>,
315315
{
316316
let peek = match tri!(self.parse_whitespace()) {
317317
Some(b) => b,
@@ -335,6 +335,79 @@ impl<'de, R: Read<'de>> Deserializer<R> {
335335
}
336336
}
337337

338+
#[cfg(feature = "float_roundtrip")]
339+
pub(crate) fn do_deserialize_f32<'any, V>(&mut self, visitor: V) -> Result<V::Value>
340+
where
341+
V: de::Visitor<'any>,
342+
{
343+
self.single_precision = true;
344+
let val = self.deserialize_number(visitor);
345+
self.single_precision = false;
346+
val
347+
}
348+
349+
pub(crate) fn do_deserialize_i128<'any, V>(&mut self, visitor: V) -> Result<V::Value>
350+
where
351+
V: de::Visitor<'any>,
352+
{
353+
let mut buf = String::new();
354+
355+
match tri!(self.parse_whitespace()) {
356+
Some(b'-') => {
357+
self.eat_char();
358+
buf.push('-');
359+
}
360+
Some(_) => {}
361+
None => {
362+
return Err(self.peek_error(ErrorCode::EofWhileParsingValue));
363+
}
364+
};
365+
366+
tri!(self.scan_integer128(&mut buf));
367+
368+
let value = match buf.parse() {
369+
Ok(int) => visitor.visit_i128(int),
370+
Err(_) => {
371+
return Err(self.error(ErrorCode::NumberOutOfRange));
372+
}
373+
};
374+
375+
match value {
376+
Ok(value) => Ok(value),
377+
Err(err) => Err(self.fix_position(err)),
378+
}
379+
}
380+
381+
pub(crate) fn do_deserialize_u128<'any, V>(&mut self, visitor: V) -> Result<V::Value>
382+
where
383+
V: de::Visitor<'any>,
384+
{
385+
match tri!(self.parse_whitespace()) {
386+
Some(b'-') => {
387+
return Err(self.peek_error(ErrorCode::NumberOutOfRange));
388+
}
389+
Some(_) => {}
390+
None => {
391+
return Err(self.peek_error(ErrorCode::EofWhileParsingValue));
392+
}
393+
}
394+
395+
let mut buf = String::new();
396+
tri!(self.scan_integer128(&mut buf));
397+
398+
let value = match buf.parse() {
399+
Ok(int) => visitor.visit_u128(int),
400+
Err(_) => {
401+
return Err(self.error(ErrorCode::NumberOutOfRange));
402+
}
403+
};
404+
405+
match value {
406+
Ok(value) => Ok(value),
407+
Err(err) => Err(self.fix_position(err)),
408+
}
409+
}
410+
338411
fn scan_integer128(&mut self, buf: &mut String) -> Result<()> {
339412
match tri!(self.next_char_or_null()) {
340413
b'0' => {
@@ -1258,11 +1331,15 @@ static POW10: [f64; 309] = [
12581331

12591332
macro_rules! deserialize_number {
12601333
($method:ident) => {
1334+
deserialize_number!($method, deserialize_number);
1335+
};
1336+
1337+
($method:ident, $using:ident) => {
12611338
fn $method<V>(self, visitor: V) -> Result<V::Value>
12621339
where
12631340
V: de::Visitor<'de>,
12641341
{
1265-
self.deserialize_number(visitor)
1342+
self.$using(visitor)
12661343
}
12671344
};
12681345
}
@@ -1424,77 +1501,9 @@ impl<'de, 'a, R: Read<'de>> de::Deserializer<'de> for &'a mut Deserializer<R> {
14241501
deserialize_number!(deserialize_f64);
14251502

14261503
#[cfg(feature = "float_roundtrip")]
1427-
fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value>
1428-
where
1429-
V: de::Visitor<'de>,
1430-
{
1431-
self.single_precision = true;
1432-
let val = self.deserialize_number(visitor);
1433-
self.single_precision = false;
1434-
val
1435-
}
1436-
1437-
fn deserialize_i128<V>(self, visitor: V) -> Result<V::Value>
1438-
where
1439-
V: de::Visitor<'de>,
1440-
{
1441-
let mut buf = String::new();
1442-
1443-
match tri!(self.parse_whitespace()) {
1444-
Some(b'-') => {
1445-
self.eat_char();
1446-
buf.push('-');
1447-
}
1448-
Some(_) => {}
1449-
None => {
1450-
return Err(self.peek_error(ErrorCode::EofWhileParsingValue));
1451-
}
1452-
};
1453-
1454-
tri!(self.scan_integer128(&mut buf));
1455-
1456-
let value = match buf.parse() {
1457-
Ok(int) => visitor.visit_i128(int),
1458-
Err(_) => {
1459-
return Err(self.error(ErrorCode::NumberOutOfRange));
1460-
}
1461-
};
1462-
1463-
match value {
1464-
Ok(value) => Ok(value),
1465-
Err(err) => Err(self.fix_position(err)),
1466-
}
1467-
}
1468-
1469-
fn deserialize_u128<V>(self, visitor: V) -> Result<V::Value>
1470-
where
1471-
V: de::Visitor<'de>,
1472-
{
1473-
match tri!(self.parse_whitespace()) {
1474-
Some(b'-') => {
1475-
return Err(self.peek_error(ErrorCode::NumberOutOfRange));
1476-
}
1477-
Some(_) => {}
1478-
None => {
1479-
return Err(self.peek_error(ErrorCode::EofWhileParsingValue));
1480-
}
1481-
}
1482-
1483-
let mut buf = String::new();
1484-
tri!(self.scan_integer128(&mut buf));
1485-
1486-
let value = match buf.parse() {
1487-
Ok(int) => visitor.visit_u128(int),
1488-
Err(_) => {
1489-
return Err(self.error(ErrorCode::NumberOutOfRange));
1490-
}
1491-
};
1492-
1493-
match value {
1494-
Ok(value) => Ok(value),
1495-
Err(err) => Err(self.fix_position(err)),
1496-
}
1497-
}
1504+
deserialize_number!(deserialize_f32, do_deserialize_f32);
1505+
deserialize_number!(deserialize_i128, do_deserialize_i128);
1506+
deserialize_number!(deserialize_u128, do_deserialize_u128);
14981507

14991508
fn deserialize_char<V>(self, visitor: V) -> Result<V::Value>
15001509
where

src/value/de.rs

+35-20
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::error::Error;
1+
use crate::error::{Error, ErrorCode};
22
use crate::map::Map;
33
use crate::number::Number;
44
use crate::value::Value;
@@ -1121,18 +1121,29 @@ struct MapKeyDeserializer<'de> {
11211121
}
11221122

11231123
macro_rules! deserialize_numeric_key {
1124-
($method:ident => $visit:ident) => {
1124+
($method:ident) => {
1125+
deserialize_numeric_key!($method, deserialize_number);
1126+
};
1127+
1128+
($method:ident, $using:ident) => {
11251129
fn $method<V>(self, visitor: V) -> Result<V::Value, Error>
11261130
where
11271131
V: Visitor<'de>,
11281132
{
1129-
let parsed = crate::from_str(&self.key);
1130-
match (parsed, self.key) {
1131-
(Ok(integer), _) => visitor.$visit(integer),
1132-
(Err(_), Cow::Borrowed(s)) => visitor.visit_borrowed_str(s),
1133-
#[cfg(any(feature = "std", feature = "alloc"))]
1134-
(Err(_), Cow::Owned(s)) => visitor.visit_string(s),
1133+
let mut de = crate::Deserializer::from_str(&self.key);
1134+
1135+
match tri!(de.peek()) {
1136+
Some(b'0'..=b'9' | b'-') => {}
1137+
_ => return Err(Error::syntax(ErrorCode::ExpectedNumericKey, 0, 0)),
11351138
}
1139+
1140+
let number = tri!(de.$using(visitor));
1141+
1142+
if tri!(de.peek()).is_some() {
1143+
return Err(Error::syntax(ErrorCode::ExpectedNumericKey, 0, 0));
1144+
}
1145+
1146+
Ok(number)
11361147
}
11371148
};
11381149
}
@@ -1147,18 +1158,22 @@ impl<'de> serde::Deserializer<'de> for MapKeyDeserializer<'de> {
11471158
BorrowedCowStrDeserializer::new(self.key).deserialize_any(visitor)
11481159
}
11491160

1150-
deserialize_numeric_key!(deserialize_i8 => visit_i8);
1151-
deserialize_numeric_key!(deserialize_i16 => visit_i16);
1152-
deserialize_numeric_key!(deserialize_i32 => visit_i32);
1153-
deserialize_numeric_key!(deserialize_i64 => visit_i64);
1154-
deserialize_numeric_key!(deserialize_i128 => visit_i128);
1155-
deserialize_numeric_key!(deserialize_u8 => visit_u8);
1156-
deserialize_numeric_key!(deserialize_u16 => visit_u16);
1157-
deserialize_numeric_key!(deserialize_u32 => visit_u32);
1158-
deserialize_numeric_key!(deserialize_u64 => visit_u64);
1159-
deserialize_numeric_key!(deserialize_u128 => visit_u128);
1160-
deserialize_numeric_key!(deserialize_f32 => visit_f32);
1161-
deserialize_numeric_key!(deserialize_f64 => visit_f64);
1161+
deserialize_numeric_key!(deserialize_i8);
1162+
deserialize_numeric_key!(deserialize_i16);
1163+
deserialize_numeric_key!(deserialize_i32);
1164+
deserialize_numeric_key!(deserialize_i64);
1165+
deserialize_numeric_key!(deserialize_u8);
1166+
deserialize_numeric_key!(deserialize_u16);
1167+
deserialize_numeric_key!(deserialize_u32);
1168+
deserialize_numeric_key!(deserialize_u64);
1169+
#[cfg(not(feature = "float_roundtrip"))]
1170+
deserialize_numeric_key!(deserialize_f32);
1171+
deserialize_numeric_key!(deserialize_f64);
1172+
1173+
#[cfg(feature = "float_roundtrip")]
1174+
deserialize_numeric_key!(deserialize_f32, do_deserialize_f32);
1175+
deserialize_numeric_key!(deserialize_i128, do_deserialize_i128);
1176+
deserialize_numeric_key!(deserialize_u128, do_deserialize_u128);
11621177

11631178
#[inline]
11641179
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Error>

tests/test.rs

+6
Original file line numberDiff line numberDiff line change
@@ -1907,6 +1907,12 @@ fn test_integer_key() {
19071907
),
19081908
(r#"{"123 ":null}"#, "expected `\"` at line 1 column 6"),
19091909
]);
1910+
1911+
let err = from_value::<BTreeMap<i32, ()>>(json!({" 123":null})).unwrap_err();
1912+
assert_eq!(err.to_string(), "invalid value: expected key to be a number in quotes");
1913+
1914+
let err = from_value::<BTreeMap<i32, ()>>(json!({"123 ":null})).unwrap_err();
1915+
assert_eq!(err.to_string(), "invalid value: expected key to be a number in quotes");
19101916
}
19111917

19121918
#[test]

0 commit comments

Comments
 (0)