ethabi_next/
tuple_param.rs

1// Copyright 2020 Parity Technologies
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9//! Tuple param type.
10
11use crate::ParamType;
12use serde::{
13	de::{Error, MapAccess, Visitor},
14	Deserialize, Deserializer,
15};
16use std::fmt;
17
18/// Tuple params specification
19#[derive(Debug, Clone, PartialEq)]
20pub struct TupleParam {
21	/// Param name.
22	pub name: Option<String>,
23
24	/// Param type.
25	pub kind: ParamType,
26}
27
28impl<'a> Deserialize<'a> for TupleParam {
29	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
30	where
31		D: Deserializer<'a>,
32	{
33		deserializer.deserialize_any(TupleParamVisitor)
34	}
35}
36
37struct TupleParamVisitor;
38
39impl<'a> Visitor<'a> for TupleParamVisitor {
40	type Value = TupleParam;
41
42	fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
43		write!(formatter, "a valid tuple parameter spec")
44	}
45
46	fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
47	where
48		A: MapAccess<'a>,
49	{
50		let mut name = None;
51		let mut kind = None;
52		let mut components = None;
53
54		while let Some(ref key) = map.next_key::<String>()? {
55			match key.as_ref() {
56				"name" => {
57					if name.is_some() {
58						return Err(Error::duplicate_field("name"));
59					}
60					name = Some(map.next_value()?);
61				}
62				"type" => {
63					if kind.is_some() {
64						return Err(Error::duplicate_field("type"));
65					}
66					kind = Some(map.next_value()?);
67				}
68				"components" => {
69					if components.is_some() {
70						return Err(Error::duplicate_field("components"));
71					}
72					let component: Vec<TupleParam> = map.next_value()?;
73					components = Some(component)
74				}
75				_ => {}
76			}
77		}
78
79		let kind = kind.ok_or_else(|| Error::missing_field("kind")).and_then(|param_type| match param_type {
80			ParamType::Tuple(_) => {
81				let tuple_params = components.ok_or_else(|| Error::missing_field("components"))?;
82				Ok(ParamType::Tuple(tuple_params.into_iter().map(|param| param.kind).collect()))
83			}
84			ParamType::Array(ref inner) => {
85				if let ParamType::Tuple(_) = **inner {
86					let tuple_params = components.ok_or_else(|| Error::missing_field("components"))?;
87					Ok(ParamType::Array(Box::new(ParamType::Tuple(
88						tuple_params.into_iter().map(|param| param.kind).collect(),
89					))))
90				} else {
91					Ok(param_type)
92				}
93			}
94			ParamType::FixedArray(ref inner, size) => {
95				if let ParamType::Tuple(_) = **inner {
96					let tuple_params = components.ok_or_else(|| Error::missing_field("components"))?;
97					Ok(ParamType::FixedArray(
98						Box::new(ParamType::Tuple(tuple_params.into_iter().map(|param| param.kind).collect())),
99						size,
100					))
101				} else {
102					Ok(param_type)
103				}
104			}
105			_ => Ok(param_type),
106		})?;
107
108		Ok(TupleParam { name, kind })
109	}
110}
111
112#[cfg(test)]
113mod tests {
114	use crate::{ParamType, TupleParam};
115
116	#[test]
117	fn tuple_param_deserialization() {
118		let s = r#"[{
119			"name": "foo",
120			"type": "address"
121			},{
122			"name": "bar",
123			"type": "address"
124			},{
125			"name": "baz",
126			"type": "address"
127			},{
128			"type": "bool"
129			}
130		]"#;
131
132		let deserialized: Vec<TupleParam> = serde_json::from_str(s).unwrap();
133
134		assert_eq!(
135			deserialized,
136			vec![
137				TupleParam { name: Some(String::from("foo")), kind: ParamType::Address },
138				TupleParam { name: Some(String::from("bar")), kind: ParamType::Address },
139				TupleParam { name: Some(String::from("baz")), kind: ParamType::Address },
140				TupleParam { name: None, kind: ParamType::Bool },
141			]
142		);
143	}
144}