diff --git a/src/numberparse/correct.rs b/src/numberparse/correct.rs index 4d2f9237..b7706256 100644 --- a/src/numberparse/correct.rs +++ b/src/numberparse/correct.rs @@ -191,11 +191,12 @@ impl<'de> Deserializer<'de> { } else if is_structural_or_whitespace(get!(buf, idx)) == 0 { err!(idx, get!(buf, idx)) } else { - Ok(StaticNode::I64(if negative { - unsafe { static_cast_i64!(num.wrapping_neg()) } // -(num as i64) + Ok(if negative { + StaticNode::I64(unsafe { static_cast_i64!(num.wrapping_neg()) }) + // -(num as i64) } else { - num as i64 - })) + StaticNode::U64(num) + }) } } } @@ -238,7 +239,6 @@ fn parse_large_integer( (true, 9_223_372_036_854_775_808) => Ok(StaticNode::I64(i64::MIN)), (true, 9_223_372_036_854_775_809..=u64::MAX) => err!(idx, get!(buf, idx)), (true, 0..=9_223_372_036_854_775_807) => Ok(StaticNode::I64(-(num as i64))), - (false, 0..=9_223_372_036_854_775_807) => Ok(StaticNode::I64(num as i64)), (false, _) => Ok(StaticNode::U64(num)), } } @@ -404,6 +404,7 @@ mod test { use crate::value::owned::Value::Static; use value_trait::StaticNode::F64; use value_trait::StaticNode::I64; + use value_trait::StaticNode::U64; fn to_value_from_str(buf: &str) -> Result { let mut val = String::from(buf); @@ -530,7 +531,7 @@ mod test { #[test] fn zero_int() -> Result<(), crate::Error> { - assert_eq!(to_value_from_str("0")?, Static(I64(0))); + assert_eq!(to_value_from_str("0")?, Static(U64(0))); Ok(()) } @@ -545,8 +546,9 @@ mod test { #[test] fn int() -> Result<(), crate::Error> { - assert_eq!(to_value_from_str("1")?, Static(I64(1))); - assert_eq!(to_value_from_str("257")?, Static(I64(257))); + assert!(matches!(to_value_from_str("1")?, Static(U64(1)))); + assert_eq!(to_value_from_str("-1")?, Static(I64(-1))); + assert_eq!(to_value_from_str("257")?, Static(U64(257))); Ok(()) } diff --git a/src/serde.rs b/src/serde.rs index e3cc2d7b..e4536b19 100644 --- a/src/serde.rs +++ b/src/serde.rs @@ -100,6 +100,7 @@ where { let mut deserializer = stry!(Deserializer::from_slice(s.as_bytes_mut())); + dbg!(&deserializer.tape); T::deserialize(&mut deserializer) } @@ -222,7 +223,8 @@ impl<'de> Deserializer<'de> { #[cfg_attr(not(feature = "no-inline"), inline)] #[allow(clippy::cast_sign_loss)] fn parse_u16(&mut self) -> Result { - match unsafe { self.next_() } { + let next = unsafe { self.next_() }; + match next { Node::Static(s) => s .as_u16() .ok_or_else(|| Self::error(ErrorType::ExpectedUnsigned)), diff --git a/src/serde/de.rs b/src/serde/de.rs index c5c9fba8..9c94e559 100644 --- a/src/serde/de.rs +++ b/src/serde/de.rs @@ -576,3 +576,6 @@ impl<'de, 'a> de::Deserializer<'de> for MapKey<'de, 'a> { struct identifier ignored_any } } + +#[cfg(test)] +mod tests; diff --git a/src/serde/de/tests.rs b/src/serde/de/tests.rs new file mode 100644 index 00000000..3367c93a --- /dev/null +++ b/src/serde/de/tests.rs @@ -0,0 +1,109 @@ +use serde::{ + de::{Error as DeError, Visitor}, + Deserialize, Deserializer, +}; +use std::fmt::{Formatter, Result as FmtResult}; + +const JSON: &str = r#"{ + "channels": [ + { + "default_auto_archive_duration": 10080 + } + ], + "unavailable": false +}"#; + +#[derive(Clone, Debug, Deserialize, Eq, PartialEq)] +#[serde(untagged)] +pub enum GuildCreate { + Available(Guild), + Unavailable(UnavailableGuild), +} + +#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq)] +pub struct UnavailableGuild { + pub unavailable: bool, +} + +#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Hash)] +pub struct Guild { + pub channels: Vec, +} + +#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq)] +pub struct Channel { + pub default_auto_archive_duration: Option, +} + +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +// Fix 1: Uncomment this and comment the handwritten deser impl. +// #[derive(Deserialize)] +// #[serde(from = "u16")] +pub enum AutoArchiveDuration { + Hour, + Day, + ThreeDays, + Week, + Unknown { value: u16 }, +} + +impl From for AutoArchiveDuration { + fn from(value: u16) -> Self { + match value { + 60 => Self::Hour, + 1440 => Self::Day, + 4320 => Self::ThreeDays, + 10080 => Self::Week, + value => Self::Unknown { value }, + } + } +} + +impl<'de> Deserialize<'de> for AutoArchiveDuration { + fn deserialize>(deserializer: D) -> Result { + deserializer.deserialize_u16(U16EnumVisitor).map(u16::into) + } +} + +pub struct U16EnumVisitor; + +impl<'de> Visitor<'de> for U16EnumVisitor { + type Value = u16; + + fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult { + f.write_str("u16") + } + + fn visit_u16(self, value: u16) -> Result { + Ok(value) + } + + fn visit_u64(self, v: u64) -> Result + where + E: DeError, + { + v.try_into().map_err(DeError::custom) + } + + // Fix 2: Uncomment this + // fn visit_i64(self, v: i64) -> Result + // where + // E: DeError, + // { + // v.try_into().map_err(DeError::custom) + // } +} + +#[test] +fn test_deser_u16() -> Result<(), Box> { + unsafe { + let mut json = JSON.to_string(); + let a = dbg!(crate::from_str::(&mut json)?); + let b = dbg!(crate::from_str::(&mut json)?); + let c = dbg!(crate::from_str::(&mut json)?); + assert_eq!(a, serde_json::from_str::(&json)?); + assert_eq!(b, serde_json::from_str::(&json)?); + assert_eq!(c, serde_json::from_str::(&json)?); + }; + Ok(()) +}