From d96858d38c1d6a78ffef8799ddb59eeb6926e847 Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 15 Mar 2016 18:17:48 +0100 Subject: [PATCH] proper blockchain json parsing --- Cargo.lock | 13 +++++ Cargo.toml | 1 + json/Cargo.toml | 21 ++++++++ json/build.rs | 45 ++++++++++++++++ json/src/blockchain/account.rs | 30 +++++++++++ json/src/blockchain/block.rs | 35 +++++++++++++ json/src/blockchain/blockchain.rs | 35 +++++++++++++ json/src/blockchain/header.rs | 51 ++++++++++++++++++ json/src/blockchain/mod.rs | 25 +++++++++ json/src/blockchain/state.rs | 34 ++++++++++++ json/src/blockchain/test.rs | 32 ++++++++++++ json/src/blockchain/transaction.rs | 35 +++++++++++++ json/src/bytes.rs | 81 ++++++++++++++++++++++++++++ json/src/hash.rs | 81 ++++++++++++++++++++++++++++ json/src/lib.rs | 28 ++++++++++ json/src/lib.rs.in | 25 +++++++++ json/src/uint.rs | 84 ++++++++++++++++++++++++++++++ 17 files changed, 656 insertions(+) create mode 100644 json/Cargo.toml create mode 100644 json/build.rs create mode 100644 json/src/blockchain/account.rs create mode 100644 json/src/blockchain/block.rs create mode 100644 json/src/blockchain/blockchain.rs create mode 100644 json/src/blockchain/header.rs create mode 100644 json/src/blockchain/mod.rs create mode 100644 json/src/blockchain/state.rs create mode 100644 json/src/blockchain/test.rs create mode 100644 json/src/blockchain/transaction.rs create mode 100644 json/src/bytes.rs create mode 100644 json/src/hash.rs create mode 100644 json/src/lib.rs create mode 100644 json/src/lib.rs.in create mode 100644 json/src/uint.rs diff --git a/Cargo.lock b/Cargo.lock index dfe37dbb4..f099dc670 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,7 @@ dependencies = [ "ethcore-devtools 1.1.0", "ethcore-rpc 1.1.0", "ethcore-util 1.1.0", + "ethjson 0.1.0", "ethminer 1.1.0", "ethsync 1.1.0", "fdlimit 0.1.0", @@ -286,6 +287,18 @@ dependencies = [ "vergen 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ethjson" +version = "0.1.0" +dependencies = [ + "ethcore-util 1.1.0", + "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_codegen 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syntex 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ethminer" version = "1.1.0" diff --git a/Cargo.toml b/Cargo.toml index 782dd1c79..fd1d16cff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ ethsync = { path = "sync" } ethminer = { path = "miner" } ethcore-devtools = { path = "devtools" } ethcore-rpc = { path = "rpc", optional = true } +ethjson = { path = "json" } [features] default = ["rpc"] diff --git a/json/Cargo.toml b/json/Cargo.toml new file mode 100644 index 000000000..61599c331 --- /dev/null +++ b/json/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "ethjson" +version = "0.1.0" +authors = ["debris "] +build = "build.rs" + +[dependencies] +ethcore-util = { path = "../util" } +rustc-serialize = "0.3" +serde = "0.7.0" +serde_json = "0.7.0" +serde_macros = { version = "0.7.0", optional = true } +clippy = { version = "0.0.50", optional = true } + +[build-dependencies] +serde_codegen = { version = "0.7.0", optional = true } +syntex = "0.29.0" + +[features] +default = ["serde_codegen"] +nightly = ["serde_macros"] diff --git a/json/build.rs b/json/build.rs new file mode 100644 index 000000000..a23790d86 --- /dev/null +++ b/json/build.rs @@ -0,0 +1,45 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity 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. + +// Parity 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 Parity. If not, see . + +#[cfg(not(feature = "serde_macros"))] +mod inner { + extern crate syntex; + extern crate serde_codegen; + + use std::env; + use std::path::Path; + + pub fn main() { + let out_dir = env::var_os("OUT_DIR").unwrap(); + + let src = Path::new("src/lib.rs.in"); + let dst = Path::new(&out_dir).join("lib.rs"); + + let mut registry = syntex::Registry::new(); + + serde_codegen::register(&mut registry); + registry.expand("", &src, &dst).unwrap(); + } +} + +#[cfg(feature = "serde_macros")] +mod inner { + pub fn main() {} +} + +fn main() { + inner::main(); +} diff --git a/json/src/blockchain/account.rs b/json/src/blockchain/account.rs new file mode 100644 index 000000000..0d72d7fd7 --- /dev/null +++ b/json/src/blockchain/account.rs @@ -0,0 +1,30 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity 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. + +// Parity 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 Parity. If not, see . + +//! Blockchain test account deserializer. + +use std::collections::BTreeMap; +use uint::Uint; +use bytes::Bytes; + +/// Blockchain test account deserializer. +#[derive(Debug, PartialEq, Deserialize)] +pub struct Account { + balance: Uint, + code: Bytes, + nonce: Uint, + storage: BTreeMap, +} diff --git a/json/src/blockchain/block.rs b/json/src/blockchain/block.rs new file mode 100644 index 000000000..5dd423e7c --- /dev/null +++ b/json/src/blockchain/block.rs @@ -0,0 +1,35 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity 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. + +// Parity 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 Parity. If not, see . + +//! Blockchain test block deserializer. + +use uint::Uint; +use bytes::Bytes; +use blockchain::header::Header; +use blockchain::transaction::Transaction; + +/// Blockchain test block deserializer. +#[derive(Debug, PartialEq, Deserialize)] +pub struct Block { + #[serde(rename="blockHeader")] + header: Header, + #[serde(rename="blocknumber")] + number: Uint, + rlp: Bytes, + transactions: Vec, + #[serde(rename="uncleHeaders")] + uncles: Vec
, +} diff --git a/json/src/blockchain/blockchain.rs b/json/src/blockchain/blockchain.rs new file mode 100644 index 000000000..675e10718 --- /dev/null +++ b/json/src/blockchain/blockchain.rs @@ -0,0 +1,35 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity 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. + +// Parity 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 Parity. If not, see . + +//! Blockchain deserialization. + +use bytes::Bytes; +use blockchain::state::State; +use blockchain::header::Header; + +/// Blockchain deserialization. +#[derive(Debug, PartialEq, Deserialize)] +pub struct BlockChain { + #[serde(rename="genesisBlockHeader")] + genesis_block: Header, + #[serde(rename="genesisRLP")] + genesis_rlp: Bytes, + blocks: Vec
, + #[serde(rename="postState")] + post_state: State, + #[serde(rename="preState")] + pre_state: State, +} diff --git a/json/src/blockchain/header.rs b/json/src/blockchain/header.rs new file mode 100644 index 000000000..ea58c76a1 --- /dev/null +++ b/json/src/blockchain/header.rs @@ -0,0 +1,51 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity 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. + +// Parity 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 Parity. If not, see . + +//! Blockchain test header deserializer. + +use hash::Hash; +use uint::Uint; +use bytes::Bytes; + +/// Blockchain test header deserializer. +#[derive(Debug, PartialEq, Deserialize)] +pub struct Header { + bloom: Hash, // TODO Bloom + coinbase: Hash, + difficulty: Uint, + #[serde(rename="extraData")] + extra_data: Bytes, + #[serde(rename="gasLimit")] + gas_limit: Uint, + #[serde(rename="gasUsed")] + gas_used: Uint, + hash: Hash, + #[serde(rename="mixHash")] + mix_hash: Hash, + nonce: Uint, // TODO fix parsing + number: Uint, + #[serde(rename="parentHash")] + parent_hash: Hash, + #[serde(rename="receiptTrie")] + receipt_trie: Hash, + #[serde(rename="stateRoot")] + state_root: Hash, + timestamp: Uint, + #[serde(rename="transactionsTrie")] + transactions_trie: Hash, + #[serde(rename="uncleHash")] + uncle_hash: Hash, +} diff --git a/json/src/blockchain/mod.rs b/json/src/blockchain/mod.rs new file mode 100644 index 000000000..046b2e534 --- /dev/null +++ b/json/src/blockchain/mod.rs @@ -0,0 +1,25 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity 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. + +// Parity 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 Parity. If not, see . + +//! Blockchain test deserialization. + +pub mod account; +pub mod block; +pub mod blockchain; +pub mod header; +pub mod state; +pub mod transaction; +pub mod test; diff --git a/json/src/blockchain/state.rs b/json/src/blockchain/state.rs new file mode 100644 index 000000000..c934d7c0a --- /dev/null +++ b/json/src/blockchain/state.rs @@ -0,0 +1,34 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity 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. + +// Parity 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 Parity. If not, see . + +//! Blockchain test state deserializer. + +use std::collections::BTreeMap; +use std::ops::Deref; +use hash::Hash; +use blockchain::account::Account; + +/// Blockchain test state deserializer. +#[derive(Debug, PartialEq, Deserialize)] +pub struct State(BTreeMap); + +impl Deref for State { + type Target = BTreeMap; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} diff --git a/json/src/blockchain/test.rs b/json/src/blockchain/test.rs new file mode 100644 index 000000000..6097a60e6 --- /dev/null +++ b/json/src/blockchain/test.rs @@ -0,0 +1,32 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity 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. + +// Parity 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 Parity. If not, see . + +//! Blockchain test deserializer. + +use std::collections::BTreeMap; +use std::ops::Deref; +use blockchain::blockchain::BlockChain; + +/// Blockchain test deserializer. +pub struct Test(BTreeMap); + +impl Deref for Test { + type Target = BTreeMap; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} diff --git a/json/src/blockchain/transaction.rs b/json/src/blockchain/transaction.rs new file mode 100644 index 000000000..5d04748f5 --- /dev/null +++ b/json/src/blockchain/transaction.rs @@ -0,0 +1,35 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity 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. + +// Parity 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 Parity. If not, see . + +//! Blockchain test transaction deserialization. + +use uint::Uint; +use bytes::Bytes; + +/// Blockchain test transaction deserialization. +#[derive(Debug, PartialEq, Deserialize)] +pub struct Transaction { + data: Bytes, + #[serde(rename="gasLimit")] + gas_limit: Uint, + #[serde(rename="gasPrice")] + gas_price: Uint, + nonce: Uint, + r: Uint, + s: Uint, + v: Uint, + value: Uint +} diff --git a/json/src/bytes.rs b/json/src/bytes.rs new file mode 100644 index 000000000..034c90d62 --- /dev/null +++ b/json/src/bytes.rs @@ -0,0 +1,81 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity 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. + +// Parity 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 Parity. If not, see . + +//! Lenient bytes json deserialization for test json files. + +use rustc_serialize::hex::FromHex; +use serde::{Deserialize, Deserializer, Error}; +use serde::de::Visitor; + +/// Lenient bytes json deserialization for test json files. +#[derive(Default, Debug, PartialEq)] +pub struct Bytes(Vec); + +impl Into> for Bytes { + fn into(self) -> Vec { + self.0 + } +} + +impl Deserialize for Bytes { + fn deserialize(deserializer: &mut D) -> Result + where D: Deserializer { + deserializer.deserialize(BytesVisitor) + } +} + +struct BytesVisitor; + +impl Visitor for BytesVisitor { + type Value = Bytes; + + fn visit_str(&mut self, value: &str) -> Result where E: Error { + let v = match value.len() { + 0 => vec![], + 2 if value.starts_with("0x") => vec![], + _ if value.starts_with("0x") => try!(FromHex::from_hex(&value[2..]).map_err(|_| Error::custom("Invalid hex value."))), + _ => try!(FromHex::from_hex(value).map_err(|_| Error::custom("Invalid hex value"))) + }; + Ok(Bytes(v)) + } + + fn visit_string(&mut self, value: String) -> Result where E: Error { + self.visit_str(value.as_ref()) + } +} + +#[cfg(test)] +//mod test { + //use std::str::FromStr; + //use serde_json; + //use util::hash::H256; + //use hash::Hash; + + //#[test] + //fn uint_deserialization() { + //let s = r#"["", "5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae"]"#; + //let deserialized: Vec = serde_json::from_str(s).unwrap(); + //assert_eq!(deserialized, vec![ + //Hash(H256::from(0)), + //Hash(H256::from_str("5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae").unwrap()) + //]); + //} + + //#[test] + //fn uint_into() { + //assert_eq!(H256::from(0), Hash(H256::from(0)).into()); + //} +//} diff --git a/json/src/hash.rs b/json/src/hash.rs new file mode 100644 index 000000000..e5bbedbfa --- /dev/null +++ b/json/src/hash.rs @@ -0,0 +1,81 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity 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. + +// Parity 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 Parity. If not, see . + +//! Lenient hash json deserialization for test json files. + +use std::str::FromStr; +use serde::{Deserialize, Deserializer, Error}; +use serde::de::Visitor; +use util::hash::H256; + +/// Lenient hash json deserialization for test json files. +#[derive(Default, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct Hash(H256); + +impl Into for Hash { + fn into(self) -> H256 { + self.0 + } +} + +impl Deserialize for Hash { + fn deserialize(deserializer: &mut D) -> Result + where D: Deserializer { + deserializer.deserialize(HashVisitor) + } +} + +struct HashVisitor; + +impl Visitor for HashVisitor { + type Value = Hash; + + fn visit_str(&mut self, value: &str) -> Result where E: Error { + let value = match value.len() { + 0 => H256::from(0), + _ => try!(H256::from_str(value).map_err(|_| Error::custom("invalid hex value."))) + }; + + Ok(Hash(value)) + } + + fn visit_string(&mut self, value: String) -> Result where E: Error { + self.visit_str(value.as_ref()) + } +} + +#[cfg(test)] +mod test { + use std::str::FromStr; + use serde_json; + use util::hash::H256; + use hash::Hash; + + #[test] + fn uint_deserialization() { + let s = r#"["", "5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae"]"#; + let deserialized: Vec = serde_json::from_str(s).unwrap(); + assert_eq!(deserialized, vec![ + Hash(H256::from(0)), + Hash(H256::from_str("5a39ed1020c04d4d84539975b893a4e7c53eab6c2965db8bc3468093a31bc5ae").unwrap()) + ]); + } + + #[test] + fn uint_into() { + assert_eq!(H256::from(0), Hash(H256::from(0)).into()); + } +} diff --git a/json/src/lib.rs b/json/src/lib.rs new file mode 100644 index 000000000..b94e1fa55 --- /dev/null +++ b/json/src/lib.rs @@ -0,0 +1,28 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity 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. + +// Parity 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 Parity. If not, see . + +//! Json deserialization module. + +#![warn(missing_docs)] +#![cfg_attr(feature="nightly", feature(custom_derive, custom_attribute, plugin))] +#![cfg_attr(feature="nightly", plugin(serde_macros, clippy))] + +#[cfg(feature = "serde_macros")] +include!("lib.rs.in"); + +#[cfg(not(feature = "serde_macros"))] +include!(concat!(env!("OUT_DIR"), "/lib.rs")); + diff --git a/json/src/lib.rs.in b/json/src/lib.rs.in new file mode 100644 index 000000000..6d3437811 --- /dev/null +++ b/json/src/lib.rs.in @@ -0,0 +1,25 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity 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. + +// Parity 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 Parity. If not, see . + +extern crate rustc_serialize; +extern crate serde; +extern crate serde_json; +extern crate ethcore_util as util; + +pub mod hash; +pub mod uint; +pub mod bytes; +pub mod blockchain; diff --git a/json/src/uint.rs b/json/src/uint.rs new file mode 100644 index 000000000..f7f34f1dd --- /dev/null +++ b/json/src/uint.rs @@ -0,0 +1,84 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity 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. + +// Parity 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 Parity. If not, see . + +//! Lenient uint json deserialization for test json files. + +use std::str::FromStr; +use serde::{Deserialize, Deserializer, Error}; +use serde::de::Visitor; +use util::numbers::{U256, Uint as U}; + +/// Lenient uint json deserialization for test json files. +#[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Uint(U256); + +impl Into for Uint { + fn into(self) -> U256 { + self.0 + } +} + +impl Deserialize for Uint { + fn deserialize(deserializer: &mut D) -> Result + where D: Deserializer { + deserializer.deserialize(UintVisitor) + } +} + +struct UintVisitor; + +impl Visitor for UintVisitor { + type Value = Uint; + + fn visit_str(&mut self, value: &str) -> Result where E: Error { + let value = match value.len() { + 0 => U256::from(0), + 2 if value.starts_with("0x") => U256::from(0), + _ if value.starts_with("0x") => try!(U256::from_str(&value[2..]).map_err(|_| Error::custom("invalid hex value."))), + _ => try!(U256::from_dec_str(value).map_err(|_| Error::custom("invalid decimal value."))) + }; + + Ok(Uint(value)) + } + + fn visit_string(&mut self, value: String) -> Result where E: Error { + self.visit_str(value.as_ref()) + } +} + +#[cfg(test)] +mod test { + use serde_json; + use util::numbers::U256; + use uint::Uint; + + #[test] + fn uint_deserialization() { + let s = r#"["0xa", "10", "", "0x"]"#; + let deserialized: Vec = serde_json::from_str(s).unwrap(); + assert_eq!(deserialized, vec![ + Uint(U256::from(10)), + Uint(U256::from(10)), + Uint(U256::from(0)), + Uint(U256::from(0)) + ]); + } + + #[test] + fn uint_into() { + assert_eq!(U256::from(10), Uint(U256::from(10)).into()); + } +}