openethereum/crates/ethjson/src/trie/input.rs

180 lines
5.1 KiB
Rust

// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// OpenEthereum is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
//! Trie test input deserialization.
use crate::bytes::Bytes;
use serde::{
de::{Error as ErrorTrait, MapAccess, SeqAccess, Visitor},
Deserialize, Deserializer,
};
use std::{collections::BTreeMap, fmt, str::FromStr};
/// Trie test input.
#[derive(Debug, PartialEq)]
pub struct Input {
/// Input params.
pub data: BTreeMap<Bytes, Option<Bytes>>,
}
impl<'a> Deserialize<'a> for Input {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'a>,
{
deserializer.deserialize_any(InputVisitor)
}
}
struct InputVisitor;
impl<'a> Visitor<'a> for InputVisitor {
type Value = Input;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a map of bytes into bytes")
}
fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
where
V: MapAccess<'a>,
{
let mut result = BTreeMap::new();
loop {
let key_str: Option<String> = visitor.next_key()?;
let key = match key_str {
Some(ref k) if k.starts_with("0x") => {
Bytes::from_str(k).map_err(V::Error::custom)?
}
Some(k) => Bytes::new(k.into_bytes()),
None => {
break;
}
};
let val_str: Option<String> = visitor.next_value()?;
let val = match val_str {
Some(ref v) if v.starts_with("0x") => {
Some(Bytes::from_str(v).map_err(V::Error::custom)?)
}
Some(v) => Some(Bytes::new(v.into_bytes())),
None => None,
};
result.insert(key, val);
}
let input = Input { data: result };
Ok(input)
}
fn visit_seq<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
where
V: SeqAccess<'a>,
{
let mut result = BTreeMap::new();
loop {
let keyval: Option<Vec<Option<String>>> = visitor.next_element()?;
let keyval = match keyval {
Some(k) => k,
_ => {
break;
}
};
if keyval.len() != 2 {
return Err(V::Error::custom("Invalid key value pair."));
}
let ref key_str: Option<String> = keyval[0];
let ref val_str: Option<String> = keyval[1];
let key = match *key_str {
Some(ref k) if k.starts_with("0x") => {
Bytes::from_str(k).map_err(V::Error::custom)?
}
Some(ref k) => Bytes::new(k.clone().into_bytes()),
None => {
break;
}
};
let val = match *val_str {
Some(ref v) if v.starts_with("0x") => {
Some(Bytes::from_str(v).map_err(V::Error::custom)?)
}
Some(ref v) => Some(Bytes::new(v.clone().into_bytes())),
None => None,
};
result.insert(key, val);
}
let input = Input { data: result };
Ok(input)
}
}
#[cfg(test)]
mod tests {
use super::Input;
use crate::bytes::Bytes;
use serde_json;
use std::collections::BTreeMap;
#[test]
fn input_deserialization_from_map() {
let s = r#"{
"0x0045" : "0x0123456789",
"be" : "e",
"0x0a" : null
}"#;
let input: Input = serde_json::from_str(s).unwrap();
let mut map = BTreeMap::new();
map.insert(
Bytes::new(vec![0, 0x45]),
Some(Bytes::new(vec![0x01, 0x23, 0x45, 0x67, 0x89])),
);
map.insert(Bytes::new(vec![0x62, 0x65]), Some(Bytes::new(vec![0x65])));
map.insert(Bytes::new(vec![0x0a]), None);
assert_eq!(input.data, map);
}
#[test]
fn input_deserialization_from_array() {
let s = r#"[
["0x0045", "0x0123456789"],
["be", "e"],
["0x0a", null]
]"#;
let input: Input = serde_json::from_str(s).unwrap();
let mut map = BTreeMap::new();
map.insert(
Bytes::new(vec![0, 0x45]),
Some(Bytes::new(vec![0x01, 0x23, 0x45, 0x67, 0x89])),
);
map.insert(Bytes::new(vec![0x62, 0x65]), Some(Bytes::new(vec![0x65])));
map.insert(Bytes::new(vec![0x0a]), None);
assert_eq!(input.data, map);
}
}