fuel_ethabi/
filter.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
9use core::ops;
10
11#[cfg(feature = "serde")]
12use serde::{Serialize, Serializer};
13
14#[cfg(not(feature = "std"))]
15use crate::no_std_prelude::*;
16use crate::{Hash, Token};
17
18/// Raw topic filter.
19#[derive(Debug, PartialEq, Default)]
20pub struct RawTopicFilter {
21	/// Topic.
22	pub topic0: Topic<Token>,
23	/// Topic.
24	pub topic1: Topic<Token>,
25	/// Topic.
26	pub topic2: Topic<Token>,
27}
28
29/// Topic filter.
30#[derive(Debug, PartialEq, Eq, Default)]
31pub struct TopicFilter {
32	/// Usually (for not-anonymous transactions) the first topic is event signature.
33	pub topic0: Topic<Hash>,
34	/// Second topic.
35	pub topic1: Topic<Hash>,
36	/// Third topic.
37	pub topic2: Topic<Hash>,
38	/// Fourth topic.
39	pub topic3: Topic<Hash>,
40}
41
42#[cfg(feature = "serde")]
43impl Serialize for TopicFilter {
44	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
45	where
46		S: Serializer,
47	{
48		vec![&self.topic0, &self.topic1, &self.topic2, &self.topic3].serialize(serializer)
49	}
50}
51
52/// Acceptable topic possibilities.
53#[derive(Debug, PartialEq, Eq)]
54pub enum Topic<T> {
55	/// Match any.
56	Any,
57	/// Match any of the hashes.
58	OneOf(Vec<T>),
59	/// Match only this hash.
60	This(T),
61}
62
63impl<T> Topic<T> {
64	/// Map
65	pub fn map<F, O>(self, f: F) -> Topic<O>
66	where
67		F: Fn(T) -> O,
68	{
69		match self {
70			Topic::Any => Topic::Any,
71			Topic::OneOf(topics) => Topic::OneOf(topics.into_iter().map(f).collect()),
72			Topic::This(topic) => Topic::This(f(topic)),
73		}
74	}
75
76	/// Returns true if topic is empty (Topic::Any)
77	pub fn is_any(&self) -> bool {
78		match *self {
79			Topic::Any => true,
80			Topic::This(_) | Topic::OneOf(_) => false,
81		}
82	}
83}
84
85impl<T> Default for Topic<T> {
86	fn default() -> Self {
87		Topic::Any
88	}
89}
90
91impl<T> From<Option<T>> for Topic<T> {
92	fn from(o: Option<T>) -> Self {
93		match o {
94			Some(topic) => Topic::This(topic),
95			None => Topic::Any,
96		}
97	}
98}
99
100impl<T> From<T> for Topic<T> {
101	fn from(topic: T) -> Self {
102		Topic::This(topic)
103	}
104}
105
106impl<T> From<Vec<T>> for Topic<T> {
107	fn from(topics: Vec<T>) -> Self {
108		Topic::OneOf(topics)
109	}
110}
111
112impl<T> From<Topic<T>> for Vec<T> {
113	fn from(topic: Topic<T>) -> Self {
114		match topic {
115			Topic::Any => vec![],
116			Topic::This(topic) => vec![topic],
117			Topic::OneOf(topics) => topics,
118		}
119	}
120}
121
122#[cfg(feature = "serde")]
123impl Serialize for Topic<Hash> {
124	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
125	where
126		S: Serializer,
127	{
128		match *self {
129			Topic::Any => Option::<()>::None.serialize(serializer),
130			Topic::OneOf(ref vec) => vec.serialize(serializer),
131			Topic::This(ref hash) => hash.serialize(serializer),
132		}
133	}
134}
135
136impl<T> ops::Index<usize> for Topic<T> {
137	type Output = T;
138
139	fn index(&self, index: usize) -> &Self::Output {
140		match *self {
141			Topic::Any => panic!("Topic unavailable"),
142			Topic::This(ref topic) => {
143				if index != 0 {
144					panic!("Topic unavailable");
145				}
146				topic
147			}
148			Topic::OneOf(ref topics) => topics.index(index),
149		}
150	}
151}
152
153#[cfg(test)]
154mod tests {
155	use super::Topic;
156	#[cfg(feature = "serde")]
157	use super::TopicFilter;
158	#[cfg(not(feature = "std"))]
159	use crate::no_std_prelude::*;
160	#[cfg(feature = "serde")]
161	use crate::Hash;
162
163	#[cfg(feature = "serde")]
164	fn hash(s: &'static str) -> Hash {
165		s.parse().unwrap()
166	}
167
168	#[cfg(feature = "serde")]
169	#[test]
170	fn test_topic_filter_serialization() {
171		let expected = r#"["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b",null,["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b","0x0000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebccc"],null]"#;
172
173		let topic = TopicFilter {
174			topic0: Topic::This(hash("000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b")),
175			topic1: Topic::Any,
176			topic2: Topic::OneOf(vec![
177				hash("000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b"),
178				hash("0000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebccc"),
179			]),
180			topic3: Topic::Any,
181		};
182
183		let topic_str = serde_json::to_string(&topic).unwrap();
184		assert_eq!(expected, &topic_str);
185	}
186
187	#[test]
188	fn test_topic_from() {
189		assert_eq!(Topic::Any as Topic<u64>, None.into());
190		assert_eq!(Topic::This(10u64), 10u64.into());
191		assert_eq!(Topic::OneOf(vec![10u64, 20]), vec![10u64, 20].into());
192	}
193
194	#[test]
195	fn test_topic_into_vec() {
196		let expected: Vec<u64> = vec![];
197		let is: Vec<u64> = (Topic::Any as Topic<u64>).into();
198		assert_eq!(expected, is);
199		let expected: Vec<u64> = vec![10];
200		let is: Vec<u64> = Topic::This(10u64).into();
201		assert_eq!(expected, is);
202		let expected: Vec<u64> = vec![10, 20];
203		let is: Vec<u64> = Topic::OneOf(vec![10u64, 20]).into();
204		assert_eq!(expected, is);
205	}
206
207	#[test]
208	fn test_topic_is_any() {
209		assert!((Topic::Any as Topic<u8>).is_any());
210		assert!(!Topic::OneOf(vec![10u64, 20]).is_any());
211		assert!(!Topic::This(10u64).is_any());
212	}
213
214	#[test]
215	fn test_topic_index() {
216		assert_eq!(Topic::OneOf(vec![10u64, 20])[0], 10);
217		assert_eq!(Topic::OneOf(vec![10u64, 20])[1], 20);
218		assert_eq!(Topic::This(10u64)[0], 10);
219	}
220
221	#[test]
222	#[should_panic(expected = "Topic unavailable")]
223	fn test_topic_index_panic() {
224		let _ = (Topic::Any as Topic<u8>)[0];
225	}
226
227	#[test]
228	#[should_panic(expected = "Topic unavailable")]
229	fn test_topic_index_panic2() {
230		assert_eq!(Topic::This(10u64)[1], 10);
231	}
232}