cfxstore/json/
hash.rs

1// Copyright 2015-2019 Parity Technologies (UK) Ltd.
2// This file is part of Parity Ethereum.
3
4// Parity Ethereum is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Parity Ethereum is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Parity Ethereum.  If not, see <http://www.gnu.org/licenses/>.
16
17use super::Error;
18use rustc_hex::{FromHex, ToHex};
19use serde::{
20    de::{Error as SerdeError, Visitor},
21    Deserialize, Deserializer, Serialize, Serializer,
22};
23use std::{cmp::Ordering, fmt, ops, str};
24
25macro_rules! impl_hash {
26    ($name:ident, $size:expr) => {
27        pub struct $name([u8; $size]);
28
29        impl $name {
30            pub fn at(&self, idx: usize) -> u8 {
31                assert!(idx < $size);
32                self.0[idx]
33            }
34        }
35
36        impl fmt::Debug for $name {
37            fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
38                let self_ref: &[u8] = &self.0;
39                write!(f, "{:?}", self_ref)
40            }
41        }
42
43        impl PartialEq for $name {
44            fn eq(&self, other: &Self) -> bool {
45                let self_ref: &[u8] = &self.0;
46                let other_ref: &[u8] = &other.0;
47                self_ref == other_ref
48            }
49        }
50
51        impl ops::Deref for $name {
52            type Target = [u8];
53
54            fn deref(&self) -> &Self::Target { &self.0 }
55        }
56
57        impl Serialize for $name {
58            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
59            where S: Serializer {
60                serializer.serialize_str(&self.0.to_hex::<String>())
61            }
62        }
63
64        impl<'a> Deserialize<'a> for $name {
65            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
66            where D: Deserializer<'a> {
67                struct HashVisitor;
68
69                impl<'b> Visitor<'b> for HashVisitor {
70                    type Value = $name;
71
72                    fn expecting(
73                        &self, formatter: &mut fmt::Formatter,
74                    ) -> fmt::Result {
75                        write!(formatter, "a hex-encoded {}", stringify!($name))
76                    }
77
78                    fn visit_str<E>(
79                        self, value: &str,
80                    ) -> Result<Self::Value, E>
81                    where E: SerdeError {
82                        value.parse().map_err(SerdeError::custom)
83                    }
84
85                    fn visit_string<E>(
86                        self, value: String,
87                    ) -> Result<Self::Value, E>
88                    where E: SerdeError {
89                        self.visit_str(value.as_ref())
90                    }
91                }
92
93                deserializer.deserialize_any(HashVisitor)
94            }
95        }
96
97        impl str::FromStr for $name {
98            type Err = Error;
99
100            fn from_str(value: &str) -> Result<Self, Self::Err> {
101                match value.from_hex::<Vec<u8>>() {
102                    Ok(ref hex) if hex.len() == $size => {
103                        let mut hash = [0u8; $size];
104                        hash.clone_from_slice(hex);
105                        Ok($name(hash))
106                    }
107                    _ => Err(Error::InvalidH256),
108                }
109            }
110        }
111
112        impl From<&'static str> for $name {
113            fn from(s: &'static str) -> Self {
114                s.parse().expect(&format!(
115                    "invalid string literal for {}: '{}'",
116                    stringify!($name),
117                    s
118                ))
119            }
120        }
121
122        impl From<[u8; $size]> for $name {
123            fn from(bytes: [u8; $size]) -> Self { $name(bytes) }
124        }
125
126        impl Into<[u8; $size]> for $name {
127            fn into(self) -> [u8; $size] { self.0 }
128        }
129    };
130}
131
132impl_hash!(H128, 16);
133impl_hash!(H160, 20);
134impl_hash!(H256, 32);
135
136// FIXME: find a better hash type.
137impl PartialOrd for H160 {
138    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
139        Some(self.cmp(other))
140    }
141}
142
143impl Eq for H160 {}
144
145impl Ord for H160 {
146    fn cmp(&self, other: &Self) -> Ordering { self.0.cmp(&other.0) }
147}