use ethcontract::json::{from_value, Value};
use ethcontract::jsonrpc::serde::Deserialize;
use ethcontract::web3::types::BlockNumber;
use std::fmt::Display;
pub struct Parser {
name: &'static str,
args: Vec<Value>,
current: usize,
}
impl Parser {
pub fn new(name: &'static str, args: Vec<Value>) -> Self {
Parser {
name,
args,
current: 0,
}
}
pub fn arg<T: for<'b> Deserialize<'b>>(&mut self) -> T {
if let Some(arg) = self.args.get_mut(self.current) {
self.current += 1;
let val = from_value(std::mem::take(arg));
self.res(val)
} else {
panic!("not enough arguments for rpc call {:?}", self.name);
}
}
pub fn arg_opt<T: for<'b> Deserialize<'b>>(&mut self) -> Option<T> {
if self.current < self.args.len() {
Some(self.arg())
} else {
None
}
}
pub fn block_number_opt(&mut self) -> Option<BlockNumber> {
let value = self.arg_opt();
value.map(|value| self.parse_block_number(value))
}
pub fn done(self) {
}
fn parse_block_number(&self, value: Value) -> BlockNumber {
match value.as_str() {
Some("latest") => BlockNumber::Latest,
Some("earliest") => BlockNumber::Earliest,
Some("pending") => BlockNumber::Pending,
Some(number) => BlockNumber::Number(self.res(number.parse())),
None => self.err("block number should be a string"),
}
}
fn res<T, E: Display>(&self, res: Result<T, E>) -> T {
res.unwrap_or_else(|err| self.err(err))
}
fn err<E: Display>(&self, err: E) -> ! {
panic!(
"argument {} for rpc call {:?} is invalid: {}",
self.current, self.name, err
)
}
}
impl Drop for Parser {
fn drop(&mut self) {
if !std::thread::panicking() && self.current < self.args.len() {
panic!("too many arguments for rpc call {:?}", self.name);
}
}
}