diff --git a/Cargo.toml b/Cargo.toml index 723ed9c..5b9ac31 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bitcoin_hashes" -version = "0.3.0" +version = "0.3.1" authors = ["Andrew Poelstra "] license = "CC0-1.0" description = "Hash functions used by rust-bitcoin which support rustc 1.14.0" diff --git a/src/serde_macros.rs b/src/serde_macros.rs index 5d7d9a8..922fa24 100644 --- a/src/serde_macros.rs +++ b/src/serde_macros.rs @@ -17,21 +17,63 @@ macro_rules! serde_impl( impl<'de> ::serde::Deserialize<'de> for $t { fn deserialize>(d: D) -> Result<$t, D::Error> { - use ::serde::de::Error; use hex::FromHex; if d.is_human_readable() { - let sl: String = ::serde::Deserialize::deserialize(d)?; - $t::from_hex(&sl).map_err(D::Error::custom) + struct HexVisitor; + + impl<'de> ::serde::de::Visitor<'de> for HexVisitor { + type Value = $t; + + fn expecting(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + formatter.write_str("an ASCII hex string") + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: ::serde::de::Error, + { + if let Ok(hex) = ::std::str::from_utf8(v) { + $t::from_hex(hex).map_err(E::custom) + } else { + return Err(E::invalid_value(::serde::de::Unexpected::Bytes(v), &self)); + } + } + + fn visit_str(self, v: &str) -> Result + where + E: ::serde::de::Error, + { + $t::from_hex(v).map_err(E::custom) + } + } + + d.deserialize_str(HexVisitor) } else { - let sl: &[u8] = ::serde::Deserialize::deserialize(d)?; - if sl.len() != $t::LEN { - Err(D::Error::invalid_length(sl.len(), &stringify!($len))) - } else { - let mut ret = [0; $len]; - ret.copy_from_slice(sl); - Ok($t(ret)) + struct BytesVisitor; + + impl<'de> ::serde::de::Visitor<'de> for BytesVisitor { + type Value = $t; + + fn expecting(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + formatter.write_str("a bytestring") + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: ::serde::de::Error, + { + if v.len() != $t::LEN { + Err(E::invalid_length(v.len(), &stringify!($len))) + } else { + let mut ret = [0; $len]; + ret.copy_from_slice(v); + Ok($t(ret)) + } + } } + + d.deserialize_bytes(BytesVisitor) } } }