diff --git a/src/lib.rs b/src/lib.rs index 7e649a10..2cf85ff0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,7 @@ extern crate serde; #[macro_use] extern crate serde_derive; extern crate serde_json; +#[macro_use] extern crate serde_plain; extern crate url; extern crate url_serde; diff --git a/src/protocol/v7.rs b/src/protocol/v7.rs index 79a5eb4d..1eb655a8 100644 --- a/src/protocol/v7.rs +++ b/src/protocol/v7.rs @@ -146,6 +146,7 @@ pub struct Stacktrace { /// Represents a thread id. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)] +#[serde(untagged)] pub enum ThreadId { /// Integer representation for the thread id Int(i64), @@ -168,6 +169,16 @@ impl fmt::Display for ThreadId { } } +/// Represents an address. +#[derive(Default, Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)] +pub struct Addr(pub u64); + +impl fmt::Display for Addr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "0x{:x}", self.0) + } +} + /// Represents a single thread. #[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] #[serde(default)] @@ -908,3 +919,37 @@ impl Serialize for DebugImage { c.serialize(serializer) } } + +impl<'de> Deserialize<'de> for Addr { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + #[derive(Deserialize)] + #[serde(untagged)] + enum Repr { + Str(String), + Uint(u64), + } + + Ok(Addr(match Repr::deserialize(deserializer).map_err(D::Error::custom)? { + Repr::Str(s) => { + if s.len() > 2 && (&s[..2] == "0x" || &s[..2] == "0X") { + u64::from_str_radix(&s[2..], 16).map_err(D::Error::custom)? + } else { + u64::from_str_radix(&s, 10).map_err(D::Error::custom)? + } + } + Repr::Uint(val) => val + })) + } +} + +impl Serialize for Addr { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str(&format!("0x{:0x}", self.0)) + } +} diff --git a/tests/test_protocol_v7.rs b/tests/test_protocol_v7.rs index 80c6796e..0b129018 100644 --- a/tests/test_protocol_v7.rs +++ b/tests/test_protocol_v7.rs @@ -485,3 +485,25 @@ fn test_full_exception_stacktrace() { \"symbol_addr\":0}],\"frames_omitted\":[1,2]}}]}}" ); } + +#[test] +fn test_addr_format() { + assert_eq!(serde_json::to_string(&v7::Addr(0)).unwrap(), "\"0x0\""); + assert_eq!(serde_json::to_string(&v7::Addr(42)).unwrap(), "\"0x2a\""); + assert_eq!(serde_json::from_str::("0").unwrap(), v7::Addr(0)); + assert_eq!(serde_json::from_str::("\"0\"").unwrap(), v7::Addr(0)); + assert_eq!(serde_json::from_str::("\"0x0\"").unwrap(), v7::Addr(0)); + assert_eq!(serde_json::from_str::("42").unwrap(), v7::Addr(42)); + assert_eq!(serde_json::from_str::("\"42\"").unwrap(), v7::Addr(42)); + assert_eq!(serde_json::from_str::("\"0x2a\"").unwrap(), v7::Addr(42)); + assert_eq!(serde_json::from_str::("\"0X2A\"").unwrap(), v7::Addr(42)); +} + +#[test] +fn test_thread_id_format() { + assert_eq!(serde_json::to_string(&v7::ThreadId::Int(0)).unwrap(), "0"); + assert_eq!(serde_json::to_string(&v7::ThreadId::Int(42)).unwrap(), "42"); + assert_eq!(serde_json::to_string(&v7::ThreadId::String("x".into())).unwrap(), "\"x\""); + assert_eq!(serde_json::from_str::("0").unwrap(), v7::ThreadId::Int(0)); + assert_eq!(serde_json::from_str::("\"0\"").unwrap(), v7::ThreadId::String("0".into())); +}