ethabi_next/
event_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//! Event param specification.
10
11use crate::{ParamType, TupleParam};
12use serde::{
13	de::{Error, MapAccess, Visitor},
14	Deserialize, Deserializer,
15};
16use std::fmt;
17
18/// Event param specification.
19#[derive(Debug, Clone, PartialEq)]
20pub struct EventParam {
21	/// Param name.
22	pub name: String,
23	/// Param type.
24	pub kind: ParamType,
25	/// Indexed flag. If true, param is used to build block bloom.
26	pub indexed: bool,
27}
28
29impl<'a> Deserialize<'a> for EventParam {
30	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
31	where
32		D: Deserializer<'a>,
33	{
34		deserializer.deserialize_any(EventParamVisitor)
35	}
36}
37
38struct EventParamVisitor;
39
40impl<'a> Visitor<'a> for EventParamVisitor {
41	type Value = EventParam;
42
43	fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
44		write!(formatter, "a valid event parameter spec")
45	}
46
47	fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
48	where
49		V: MapAccess<'a>,
50	{
51		let mut name = None;
52		let mut kind = None;
53		let mut indexed = None;
54		let mut components = None;
55
56		while let Some(ref key) = map.next_key::<String>()? {
57			match key.as_ref() {
58				"name" => {
59					if name.is_some() {
60						return Err(Error::duplicate_field("name"));
61					}
62					name = Some(map.next_value()?);
63				}
64				"type" => {
65					if kind.is_some() {
66						return Err(Error::duplicate_field("kind"));
67					}
68					kind = Some(map.next_value()?);
69				}
70				"components" => {
71					if components.is_some() {
72						return Err(Error::duplicate_field("components"));
73					}
74					let component: Vec<TupleParam> = map.next_value()?;
75					components = Some(component)
76				}
77				"indexed" => {
78					if indexed.is_some() {
79						return Err(Error::duplicate_field("indexed"));
80					}
81					indexed = Some(map.next_value()?);
82				}
83				_ => {}
84			}
85		}
86		let name = name.ok_or_else(|| Error::missing_field("name"))?;
87		let kind =
88			kind.ok_or_else(|| Error::missing_field("kind")).and_then(|param_type: ParamType| match param_type {
89				ParamType::Tuple(_) => {
90					let tuple_params = components.ok_or_else(|| Error::missing_field("components"))?;
91					Ok(ParamType::Tuple(tuple_params.into_iter().map(|param| param.kind).collect()))
92				}
93				ParamType::Array(inner_param_type) => match *inner_param_type {
94					ParamType::Tuple(_) => {
95						let tuple_params = components.ok_or_else(|| Error::missing_field("components"))?;
96						Ok(ParamType::Array(Box::new(ParamType::Tuple(
97							tuple_params.into_iter().map(|param| param.kind).collect(),
98						))))
99					}
100					_ => Ok(ParamType::Array(inner_param_type)),
101				},
102				ParamType::FixedArray(inner_param_type, size) => match *inner_param_type {
103					ParamType::Tuple(_) => {
104						let tuple_params = components.ok_or_else(|| Error::missing_field("components"))?;
105						Ok(ParamType::FixedArray(
106							Box::new(ParamType::Tuple(tuple_params.into_iter().map(|param| param.kind).collect())),
107							size,
108						))
109					}
110					_ => Ok(ParamType::FixedArray(inner_param_type, size)),
111				},
112				_ => Ok(param_type),
113			})?;
114		let indexed = indexed.unwrap_or(false);
115		Ok(EventParam { name, kind, indexed })
116	}
117}
118
119#[cfg(test)]
120mod tests {
121	use crate::{EventParam, ParamType};
122
123	#[test]
124	fn event_param_deserialization() {
125		let s = r#"{
126			"name": "foo",
127			"type": "address",
128			"indexed": true
129		}"#;
130
131		let deserialized: EventParam = serde_json::from_str(s).unwrap();
132
133		assert_eq!(deserialized, EventParam { name: "foo".to_owned(), kind: ParamType::Address, indexed: true });
134	}
135
136	#[test]
137	fn event_param_tuple_deserialization() {
138		let s = r#"{
139			"name": "foo",
140			"type": "tuple",
141			"indexed": true,
142			"components": [
143				{
144					"name": "amount",
145					"type": "uint48"
146				},
147				{
148					"name": "things",
149					"type": "tuple",
150					"components": [
151						{
152							"name": "baseTupleParam",
153							"type": "address"
154						}
155					]
156				}
157			]
158		}"#;
159
160		let deserialized: EventParam = serde_json::from_str(s).unwrap();
161
162		assert_eq!(
163			deserialized,
164			EventParam {
165				name: "foo".to_owned(),
166				kind: ParamType::Tuple(vec![ParamType::Uint(48), ParamType::Tuple(vec![ParamType::Address])]),
167				indexed: true,
168			}
169		);
170	}
171
172	#[test]
173	fn event_param_tuple_array_deserialization() {
174		let s = r#"{
175			"components": [
176				{ "type": "uint256" },
177				{ "type": "address" },
178				{
179					"components": [
180						{ "type": "address" },
181						{ "type": "address" }
182					],
183					"type": "tuple"
184				},
185				{ "type": "uint256" },
186				{
187					"components": [
188						{
189							"components": [
190								{ "type": "address" },
191								{ "type": "bytes" }
192							],
193							"type": "tuple[]"
194						},
195						{
196							"components": [
197								{ "type": "address" },
198								{ "type": "uint256" }
199							],
200							"type": "tuple[]"
201						},
202						{ "type": "uint256" }
203					],
204					"type": "tuple[]"
205				},
206				{ "type": "uint256" }
207			],
208			"indexed": false,
209			"name": "LogTaskSubmitted",
210			"type": "tuple"
211        }"#;
212
213		let deserialized: EventParam = serde_json::from_str(s).unwrap();
214
215		assert_eq!(
216			deserialized,
217			EventParam {
218				name: "LogTaskSubmitted".to_owned(),
219				kind: ParamType::Tuple(vec![
220					ParamType::Uint(256),
221					ParamType::Address,
222					ParamType::Tuple(vec![ParamType::Address, ParamType::Address]),
223					ParamType::Uint(256),
224					ParamType::Array(Box::new(ParamType::Tuple(vec![
225						ParamType::Array(Box::new(ParamType::Tuple(vec![ParamType::Address, ParamType::Bytes,]))),
226						ParamType::Array(Box::new(ParamType::Tuple(vec![ParamType::Address, ParamType::Uint(256)]))),
227						ParamType::Uint(256),
228					]))),
229					ParamType::Uint(256),
230				]),
231				indexed: false,
232			}
233		);
234	}
235}