// Copyright 2020 Parity Technologies // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Tuple param type. use crate::ParamType; use serde::{ de::{Error, MapAccess, Visitor}, Deserialize, Deserializer, }; use std::fmt; /// Tuple params specification #[derive(Debug, Clone, PartialEq)] pub struct TupleParam { /// Param name. pub name: Option, /// Param type. pub kind: ParamType, } impl<'a> Deserialize<'a> for TupleParam { fn deserialize(deserializer: D) -> Result where D: Deserializer<'a>, { deserializer.deserialize_any(TupleParamVisitor) } } struct TupleParamVisitor; impl<'a> Visitor<'a> for TupleParamVisitor { type Value = TupleParam; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { write!(formatter, "a valid tuple parameter spec") } fn visit_map(self, mut map: A) -> Result where A: MapAccess<'a>, { let mut name = None; let mut kind = None; let mut components = None; while let Some(ref key) = map.next_key::()? { match key.as_ref() { "name" => { if name.is_some() { return Err(Error::duplicate_field("name")); } name = Some(map.next_value()?); } "type" => { if kind.is_some() { return Err(Error::duplicate_field("type")); } kind = Some(map.next_value()?); } "components" => { if components.is_some() { return Err(Error::duplicate_field("components")); } let component: Vec = map.next_value()?; components = Some(component) } _ => {} } } let mut kind = kind.ok_or_else(|| Error::missing_field("kind"))?; crate::param::set_tuple_components(&mut kind, components)?; Ok(TupleParam { name, kind }) } } #[cfg(test)] mod tests { use crate::{ParamType, TupleParam}; #[test] fn tuple_param_deserialization() { let s = r#"[{ "name": "foo", "type": "address" },{ "name": "bar", "type": "address" },{ "name": "baz", "type": "address" },{ "type": "bool" } ]"#; let deserialized: Vec = serde_json::from_str(s).unwrap(); assert_eq!( deserialized, vec![ TupleParam { name: Some(String::from("foo")), kind: ParamType::Address }, TupleParam { name: Some(String::from("bar")), kind: ParamType::Address }, TupleParam { name: Some(String::from("baz")), kind: ParamType::Address }, TupleParam { name: None, kind: ParamType::Bool }, ] ); } }