1use std::str::FromStr;
20use std::fmt;
21use serde::{Deserialize, Deserializer, Serialize, Serializer};
22use serde::de::{Error, Visitor};
23use ethereum_types::{H64 as Hash64, H160 as Hash160, H256 as Hash256, H520 as Hash520, Bloom as Hash2048};
24
25macro_rules! impl_hash {
26 ($name: ident, $inner: ident) => {
27 #[derive(Default, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Clone)]
29 pub struct $name(pub $inner);
30
31 impl From<$name> for $inner {
32 fn from(other: $name) -> $inner {
33 other.0
34 }
35 }
36
37 impl From<$inner> for $name {
38 fn from(i: $inner) -> Self {
39 $name(i)
40 }
41 }
42
43 impl<'a> Deserialize<'a> for $name {
44 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
45 where D: Deserializer<'a> {
46
47 struct HashVisitor;
48
49 impl<'b> Visitor<'b> for HashVisitor {
50 type Value = $name;
51
52 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
53 write!(formatter, "a 0x-prefixed hex-encoded hash")
54 }
55
56 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> where E: Error {
57 let value = match value.len() {
58 0 => $inner::from_low_u64_be(0),
59 2 if value == "0x" => $inner::from_low_u64_be(0),
60 _ if value.starts_with("0x") => $inner::from_str(&value[2..]).map_err(|e| {
61 Error::custom(format!("Invalid hex value {}: {}", value, e).as_str())
62 })?,
63 _ => $inner::from_str(value).map_err(|e| {
64 Error::custom(format!("Invalid hex value {}: {}", value, e).as_str())
65 })?,
66 };
67
68 Ok($name(value))
69 }
70
71 fn visit_string<E>(self, value: String) -> Result<Self::Value, E> where E: Error {
72 self.visit_str(value.as_ref())
73 }
74 }
75
76 deserializer.deserialize_any(HashVisitor)
77 }
78 }
79
80 impl Serialize for $name {
81 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
82 serializer.serialize_str(&format!("{:#x}", self.0))
83 }
84 }
85 }
86}
87
88
89impl_hash!(H64, Hash64);
90impl_hash!(Address, Hash160);
91impl_hash!(H256, Hash256);
92impl_hash!(H520, Hash520);
93impl_hash!(Bloom, Hash2048);
94
95#[cfg(test)]
96mod test {
97 use super::H256;
98 use std::str::FromStr;
99
100 #[test]
101 fn hash_deserialization() {
102 let s = r#"["", "5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae"]"#;
103 let deserialized: Vec<H256> = serde_json::from_str(s).unwrap();
104 assert_eq!(deserialized, vec![
105 H256(ethereum_types::H256::zero()),
106 H256(ethereum_types::H256::from_str("5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae").unwrap())
107 ]);
108 }
109
110 #[test]
111 fn hash_into() {
112 assert_eq!(ethereum_types::H256::zero(), H256(ethereum_types::H256::zero()).into());
113 }
114}