// 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 .
use serde::{Deserialize, Deserializer, Error};
use serde_json::value;
use jsonrpc_core::Value;
use util::hash::*;
use v1::types::BlockNumber;
use ethcore::filter::Filter as EthFilter;
use ethcore::client::BlockId;
#[derive(Debug, PartialEq)]
pub enum VariadicValue where T: Deserialize {
Single(T),
Multiple(Vec),
Null,
}
impl Deserialize for VariadicValue where T: Deserialize {
fn deserialize(deserializer: &mut D) -> Result, D::Error>
where D: Deserializer {
let v = try!(Value::deserialize(deserializer));
if v.is_null() {
return Ok(VariadicValue::Null);
}
Deserialize::deserialize(&mut value::Deserializer::new(v.clone())).map(VariadicValue::Single)
.or_else(|_| Deserialize::deserialize(&mut value::Deserializer::new(v.clone())).map(VariadicValue::Multiple))
.map_err(|_| Error::custom("")) // unreachable, but types must match
}
}
pub type FilterAddress = VariadicValue;
pub type Topic = VariadicValue;
#[derive(Debug, PartialEq, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Filter {
#[serde(rename="fromBlock")]
pub from_block: Option,
#[serde(rename="toBlock")]
pub to_block: Option,
pub address: Option,
pub topics: Option>,
}
impl Into for Filter {
fn into(self) -> EthFilter {
EthFilter {
from_block: self.from_block.map_or_else(|| BlockId::Earliest, Into::into),
to_block: self.to_block.map_or_else(|| BlockId::Latest, Into::into),
address: self.address.and_then(|address| match address {
VariadicValue::Null => None,
VariadicValue::Single(a) => Some(vec![a]),
VariadicValue::Multiple(a) => Some(a)
}),
topics: {
let mut iter = self.topics.map_or_else(Vec::new, |topics| topics.into_iter().take(4).map(|topic| match topic {
VariadicValue::Null => None,
VariadicValue::Single(t) => Some(vec![t]),
VariadicValue::Multiple(t) => Some(t)
}).filter_map(|m| m).collect()).into_iter();
[iter.next(), iter.next(), iter.next(), iter.next()]
}
}
}
}
#[cfg(test)]
mod tests {
use serde_json;
use std::str::FromStr;
use util::hash::*;
use super::*;
use v1::types::BlockNumber;
#[test]
fn topic_deserialization() {
let s = r#"["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", null, ["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", "0x0000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebccc"]]"#;
let deserialized: Vec = serde_json::from_str(s).unwrap();
assert_eq!(deserialized, vec![
VariadicValue::Single(H256::from_str("000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b").unwrap()),
VariadicValue::Null,
VariadicValue::Multiple(vec![
H256::from_str("000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b").unwrap(),
H256::from_str("0000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebccc").unwrap()
])
]);
}
#[test]
fn filter_deserialization() {
let s = r#"{"fromBlock":"earliest","toBlock":"latest"}"#;
let deserialized: Filter = serde_json::from_str(s).unwrap();
assert_eq!(deserialized, Filter {
from_block: Some(BlockNumber::Earliest),
to_block: Some(BlockNumber::Latest),
address: None,
topics: None
});
}
}