Skip to content

Commit 0a58930

Browse files
committed
Fix int parsing
Signed-off-by: Heinz N. Gies <heinz@licenser.net>
1 parent 3230c99 commit 0a58930

File tree

4 files changed

+125
-9
lines changed

4 files changed

+125
-9
lines changed

src/numberparse/correct.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -191,11 +191,12 @@ impl<'de> Deserializer<'de> {
191191
} else if is_structural_or_whitespace(get!(buf, idx)) == 0 {
192192
err!(idx, get!(buf, idx))
193193
} else {
194-
Ok(StaticNode::I64(if negative {
195-
unsafe { static_cast_i64!(num.wrapping_neg()) } // -(num as i64)
194+
Ok(if negative {
195+
StaticNode::I64(unsafe { static_cast_i64!(num.wrapping_neg()) })
196+
// -(num as i64)
196197
} else {
197-
num as i64
198-
}))
198+
StaticNode::U64(num)
199+
})
199200
}
200201
}
201202
}
@@ -238,7 +239,6 @@ fn parse_large_integer(
238239
(true, 9_223_372_036_854_775_808) => Ok(StaticNode::I64(i64::MIN)),
239240
(true, 9_223_372_036_854_775_809..=u64::MAX) => err!(idx, get!(buf, idx)),
240241
(true, 0..=9_223_372_036_854_775_807) => Ok(StaticNode::I64(-(num as i64))),
241-
(false, 0..=9_223_372_036_854_775_807) => Ok(StaticNode::I64(num as i64)),
242242
(false, _) => Ok(StaticNode::U64(num)),
243243
}
244244
}
@@ -404,6 +404,7 @@ mod test {
404404
use crate::value::owned::Value::Static;
405405
use value_trait::StaticNode::F64;
406406
use value_trait::StaticNode::I64;
407+
use value_trait::StaticNode::U64;
407408

408409
fn to_value_from_str(buf: &str) -> Result<Value, Error> {
409410
let mut val = String::from(buf);
@@ -530,7 +531,7 @@ mod test {
530531

531532
#[test]
532533
fn zero_int() -> Result<(), crate::Error> {
533-
assert_eq!(to_value_from_str("0")?, Static(I64(0)));
534+
assert_eq!(to_value_from_str("0")?, Static(U64(0)));
534535
Ok(())
535536
}
536537

@@ -545,8 +546,9 @@ mod test {
545546

546547
#[test]
547548
fn int() -> Result<(), crate::Error> {
548-
assert_eq!(to_value_from_str("1")?, Static(I64(1)));
549-
assert_eq!(to_value_from_str("257")?, Static(I64(257)));
549+
assert!(matches!(to_value_from_str("1")?, Static(U64(1))));
550+
assert_eq!(to_value_from_str("-1")?, Static(I64(-1)));
551+
assert_eq!(to_value_from_str("257")?, Static(U64(257)));
550552
Ok(())
551553
}
552554

src/serde.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ where
100100
{
101101
let mut deserializer = stry!(Deserializer::from_slice(s.as_bytes_mut()));
102102

103+
dbg!(&deserializer.tape);
103104
T::deserialize(&mut deserializer)
104105
}
105106

@@ -222,7 +223,8 @@ impl<'de> Deserializer<'de> {
222223
#[cfg_attr(not(feature = "no-inline"), inline)]
223224
#[allow(clippy::cast_sign_loss)]
224225
fn parse_u16(&mut self) -> Result<u16> {
225-
match unsafe { self.next_() } {
226+
let next = unsafe { self.next_() };
227+
match next {
226228
Node::Static(s) => s
227229
.as_u16()
228230
.ok_or_else(|| Self::error(ErrorType::ExpectedUnsigned)),

src/serde/de.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,3 +576,6 @@ impl<'de, 'a> de::Deserializer<'de> for MapKey<'de, 'a> {
576576
struct identifier ignored_any
577577
}
578578
}
579+
580+
#[cfg(test)]
581+
mod tests;

src/serde/de/tests.rs

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
use serde::{
2+
de::{Error as DeError, Visitor},
3+
Deserialize, Deserializer,
4+
};
5+
use std::fmt::{Formatter, Result as FmtResult};
6+
7+
const JSON: &str = r#"{
8+
"channels": [
9+
{
10+
"default_auto_archive_duration": 10080
11+
}
12+
],
13+
"unavailable": false
14+
}"#;
15+
16+
#[derive(Clone, Debug, Deserialize, Eq, PartialEq)]
17+
#[serde(untagged)]
18+
pub enum GuildCreate {
19+
Available(Guild),
20+
Unavailable(UnavailableGuild),
21+
}
22+
23+
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq)]
24+
pub struct UnavailableGuild {
25+
pub unavailable: bool,
26+
}
27+
28+
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Hash)]
29+
pub struct Guild {
30+
pub channels: Vec<Channel>,
31+
}
32+
33+
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq)]
34+
pub struct Channel {
35+
pub default_auto_archive_duration: Option<AutoArchiveDuration>,
36+
}
37+
38+
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
39+
// Fix 1: Uncomment this and comment the handwritten deser impl.
40+
// #[derive(Deserialize)]
41+
// #[serde(from = "u16")]
42+
pub enum AutoArchiveDuration {
43+
Hour,
44+
Day,
45+
ThreeDays,
46+
Week,
47+
Unknown { value: u16 },
48+
}
49+
50+
impl From<u16> for AutoArchiveDuration {
51+
fn from(value: u16) -> Self {
52+
match value {
53+
60 => Self::Hour,
54+
1440 => Self::Day,
55+
4320 => Self::ThreeDays,
56+
10080 => Self::Week,
57+
value => Self::Unknown { value },
58+
}
59+
}
60+
}
61+
62+
impl<'de> Deserialize<'de> for AutoArchiveDuration {
63+
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
64+
deserializer.deserialize_u16(U16EnumVisitor).map(u16::into)
65+
}
66+
}
67+
68+
pub struct U16EnumVisitor;
69+
70+
impl<'de> Visitor<'de> for U16EnumVisitor {
71+
type Value = u16;
72+
73+
fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult {
74+
f.write_str("u16")
75+
}
76+
77+
fn visit_u16<E: DeError>(self, value: u16) -> Result<Self::Value, E> {
78+
Ok(value)
79+
}
80+
81+
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
82+
where
83+
E: DeError,
84+
{
85+
v.try_into().map_err(DeError::custom)
86+
}
87+
88+
// Fix 2: Uncomment this
89+
// fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
90+
// where
91+
// E: DeError,
92+
// {
93+
// v.try_into().map_err(DeError::custom)
94+
// }
95+
}
96+
97+
#[test]
98+
fn test_deser_u16() -> Result<(), Box<dyn std::error::Error>> {
99+
unsafe {
100+
let mut json = JSON.to_string();
101+
let a = dbg!(crate::from_str::<Guild>(&mut json)?);
102+
let b = dbg!(crate::from_str::<UnavailableGuild>(&mut json)?);
103+
let c = dbg!(crate::from_str::<GuildCreate>(&mut json)?);
104+
assert_eq!(a, serde_json::from_str::<Guild>(&json)?);
105+
assert_eq!(b, serde_json::from_str::<UnavailableGuild>(&json)?);
106+
assert_eq!(c, serde_json::from_str::<GuildCreate>(&json)?);
107+
};
108+
Ok(())
109+
}

0 commit comments

Comments
 (0)