ethabi_next/
param.rs

1// Copyright 2015-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//! Function param.
10
11use serde::{
12	de::{Error, MapAccess, Visitor},
13	Deserialize, Deserializer,
14};
15use std::fmt;
16
17use crate::{ParamType, TupleParam};
18
19/// Function param.
20#[derive(Debug, Clone, PartialEq)]
21pub struct Param {
22	/// Param name.
23	pub name: String,
24	/// Param type.
25	pub kind: ParamType,
26}
27
28impl<'a> Deserialize<'a> for Param {
29	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
30	where
31		D: Deserializer<'a>,
32	{
33		deserializer.deserialize_any(ParamVisitor)
34	}
35}
36
37struct ParamVisitor;
38
39impl<'a> Visitor<'a> for ParamVisitor {
40	type Value = Param;
41
42	fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
43		write!(formatter, "a valid event parameter spec")
44	}
45
46	fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
47	where
48		V: 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("kind"));
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		let name = name.ok_or_else(|| Error::missing_field("name"))?;
79		let kind =
80			kind.ok_or_else(|| Error::missing_field("kind")).and_then(|param_type: ParamType| match param_type {
81				ParamType::Tuple(_) => {
82					let tuple_params = components.ok_or_else(|| Error::missing_field("components"))?;
83					Ok(ParamType::Tuple(tuple_params.into_iter().map(|param| param.kind).collect()))
84				}
85				ParamType::Array(inner_param_type) => match *inner_param_type {
86					ParamType::Tuple(_) => {
87						let tuple_params = components.ok_or_else(|| Error::missing_field("components"))?;
88						Ok(ParamType::Array(Box::new(ParamType::Tuple(
89							tuple_params.into_iter().map(|param| param.kind).collect(),
90						))))
91					}
92					_ => Ok(ParamType::Array(inner_param_type)),
93				},
94				ParamType::FixedArray(inner_param_type, size) => match *inner_param_type {
95					ParamType::Tuple(_) => {
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					}
102					_ => Ok(ParamType::FixedArray(inner_param_type, size)),
103				},
104				_ => Ok(param_type),
105			})?;
106		Ok(Param { name, kind })
107	}
108}
109
110#[cfg(test)]
111mod tests {
112	use crate::{Param, ParamType};
113
114	#[test]
115	fn param_deserialization() {
116		let s = r#"{
117			"name": "foo",
118			"type": "address"
119		}"#;
120
121		let deserialized: Param = serde_json::from_str(s).unwrap();
122
123		assert_eq!(deserialized, Param { name: "foo".to_owned(), kind: ParamType::Address });
124	}
125
126	#[test]
127	fn param_tuple_deserialization() {
128		let s = r#"{
129			"name": "foo",
130			"type": "tuple",
131			"components": [
132				{
133					"name": "amount",
134					"type": "uint48"
135				},
136				{
137					"name": "things",
138					"type": "tuple",
139					"components": [
140						{
141							"name": "baseTupleParam",
142							"type": "address"
143						}
144					]
145				}
146			]
147		}"#;
148
149		let deserialized: Param = serde_json::from_str(s).unwrap();
150
151		assert_eq!(
152			deserialized,
153			Param {
154				name: "foo".to_owned(),
155				kind: ParamType::Tuple(vec![ParamType::Uint(48), ParamType::Tuple(vec![ParamType::Address])]),
156			}
157		);
158	}
159
160	#[test]
161	fn param_tuple_array_deserialization() {
162		let s = r#"{
163			"name": "foo",
164			"type": "tuple[]",
165			"components": [
166				{
167					"name": "amount",
168					"type": "uint48"
169				},
170				{
171					"name": "to",
172					"type": "address"
173				},
174				{
175					"name": "from",
176					"type": "address"
177				}
178			]
179		}"#;
180
181		let deserialized: Param = serde_json::from_str(s).unwrap();
182
183		assert_eq!(
184			deserialized,
185			Param {
186				name: "foo".to_owned(),
187				kind: ParamType::Array(Box::new(ParamType::Tuple(vec![
188					ParamType::Uint(48),
189					ParamType::Address,
190					ParamType::Address
191				]))),
192			}
193		);
194	}
195
196	#[test]
197	fn param_tuple_fixed_array_deserialization() {
198		let s = r#"{
199			"name": "foo",
200			"type": "tuple[2]",
201			"components": [
202				{
203					"name": "amount",
204					"type": "uint48"
205				},
206				{
207					"name": "to",
208					"type": "address"
209				},
210				{
211					"name": "from",
212					"type": "address"
213				}
214			]
215		}"#;
216
217		let deserialized: Param = serde_json::from_str(s).unwrap();
218
219		assert_eq!(
220			deserialized,
221			Param {
222				name: "foo".to_owned(),
223				kind: ParamType::FixedArray(
224					Box::new(ParamType::Tuple(vec![ParamType::Uint(48), ParamType::Address, ParamType::Address])),
225					2
226				),
227			}
228		);
229	}
230
231	#[test]
232	fn param_tuple_with_nested_tuple_arrays_deserialization() {
233		let s = r#"{
234			"name": "foo",
235			"type": "tuple",
236			"components": [
237				{
238					"name": "bar",
239					"type": "tuple[]",
240					"components": [
241						{
242							"name": "a",
243							"type": "address"
244						}
245					]
246				},
247				{
248					"name": "baz",
249					"type": "tuple[42]",
250					"components": [
251						{
252							"name": "b",
253							"type": "address"
254						}
255					]
256				}
257			]
258		}"#;
259
260		let deserialized: Param = serde_json::from_str(s).unwrap();
261
262		assert_eq!(
263			deserialized,
264			Param {
265				name: "foo".to_owned(),
266				kind: ParamType::Tuple(vec![
267					ParamType::Array(Box::new(ParamType::Tuple(vec![ParamType::Address]))),
268					ParamType::FixedArray(Box::new(ParamType::Tuple(vec![ParamType::Address])), 42,)
269				]),
270			}
271		);
272	}
273}