ethers_abi/
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, str::FromStr};
10
11use ethereum_types::H256;
12use serde::{de::Visitor, Deserialize};
13#[cfg(feature = "serde")]
14use serde::{Serialize, Serializer};
15
16#[cfg(not(feature = "std"))]
17use crate::no_std_prelude::*;
18use crate::{Error, Hash, Token};
19
20/// Raw topic filter.
21#[derive(Debug, PartialEq, Default)]
22pub struct RawTopicFilter {
23    /// Topic.
24    pub topic0: Topic<Token>,
25    /// Topic.
26    pub topic1: Topic<Token>,
27    /// Topic.
28    pub topic2: Topic<Token>,
29}
30
31/// Topic filter.
32#[derive(Debug, PartialEq, Eq, Default, Clone, Hash)]
33pub struct TopicFilter {
34    /// Usually (for not-anonymous transactions) the first topic is event signature.
35    pub topic0: Topic<Hash>,
36    /// Second topic.
37    pub topic1: Topic<Hash>,
38    /// Third topic.
39    pub topic2: Topic<Hash>,
40    /// Fourth topic.
41    pub topic3: Topic<Hash>,
42}
43
44#[cfg(feature = "serde")]
45impl Serialize for TopicFilter {
46    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
47    where
48        S: Serializer,
49    {
50        let mut data = vec![];
51
52        if self.topic0.need_serialize() {
53            data.push(&self.topic0)
54        }
55
56        if self.topic1.need_serialize() {
57            data.push(&self.topic1)
58        }
59
60        if self.topic2.need_serialize() {
61            data.push(&self.topic2)
62        }
63
64        if self.topic3.need_serialize() {
65            data.push(&self.topic3)
66        }
67
68        data.serialize(serializer)
69    }
70}
71
72#[cfg(feature = "serde")]
73impl<'de> Deserialize<'de> for TopicFilter {
74    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
75    where
76        D: serde::Deserializer<'de>,
77    {
78        let topics = Vec::<Topic<Hash>>::deserialize(deserializer)?;
79
80        if topics.len() > 4 || topics.is_empty() {
81            return Err(Error::Other("Topics > 4 or Topics == 0".into()))
82                .map_err(serde::de::Error::custom);
83        } else {
84            let none = Topic::<Hash>::Any;
85            let topic0 = topics[0].clone();
86
87            let topic1 = topics.get(1).unwrap_or(&none).clone();
88
89            let topic2 = topics.get(2).unwrap_or(&none).clone();
90
91            let topic3 = topics.get(3).unwrap_or(&none).clone();
92
93            Ok(TopicFilter {
94                topic0,
95                topic1,
96                topic2,
97                topic3,
98            })
99        }
100    }
101}
102
103/// Acceptable topic possibilities.
104#[derive(Debug, PartialEq, Eq, Clone, Hash)]
105pub enum Topic<T> {
106    /// Should skip serialize.
107    None,
108    /// Match any.
109    Any,
110    /// Match any of the hashes.
111    OneOf(Vec<T>),
112    /// Match only this hash.
113    This(T),
114}
115
116impl<T> Topic<T> {
117    /// Map
118    pub fn map<F, O>(self, f: F) -> Topic<O>
119    where
120        F: Fn(T) -> O,
121    {
122        match self {
123            Topic::None => Topic::None,
124            Topic::Any => Topic::Any,
125            Topic::OneOf(topics) => Topic::OneOf(topics.into_iter().map(f).collect()),
126            Topic::This(topic) => Topic::This(f(topic)),
127        }
128    }
129
130    /// Returns true if topic is empty (Topic::Any)
131    pub fn is_any(&self) -> bool {
132        match *self {
133            Topic::Any => true,
134            Topic::None | Topic::This(_) | Topic::OneOf(_) => false,
135        }
136    }
137    /// Returns true if topic should be serialized
138    pub fn need_serialize(&self) -> bool {
139        match *self {
140            Topic::None => false,
141            _ => true,
142        }
143    }
144}
145
146impl<T> Default for Topic<T> {
147    fn default() -> Self {
148        Topic::None
149    }
150}
151
152impl<T> From<Option<T>> for Topic<T> {
153    fn from(o: Option<T>) -> Self {
154        match o {
155            Some(topic) => Topic::This(topic),
156            None => Topic::Any,
157        }
158    }
159}
160
161impl<T> From<T> for Topic<T> {
162    fn from(topic: T) -> Self {
163        Topic::This(topic)
164    }
165}
166
167impl<T> From<Vec<T>> for Topic<T> {
168    fn from(topics: Vec<T>) -> Self {
169        Topic::OneOf(topics)
170    }
171}
172
173impl<T> From<Topic<T>> for Vec<T> {
174    fn from(topic: Topic<T>) -> Self {
175        match topic {
176            Topic::None => vec![],
177            Topic::Any => vec![],
178            Topic::This(topic) => vec![topic],
179            Topic::OneOf(topics) => topics,
180        }
181    }
182}
183
184#[cfg(feature = "serde")]
185impl Serialize for Topic<Hash> {
186    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
187    where
188        S: Serializer,
189    {
190        match *self {
191            Topic::Any | Topic::None => Option::<()>::None.serialize(serializer),
192            Topic::OneOf(ref vec) => vec.serialize(serializer),
193            Topic::This(ref hash) => hash.serialize(serializer),
194        }
195    }
196}
197
198#[cfg(feature = "serde")]
199impl<'de> Deserialize<'de> for Topic<Hash> {
200    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
201    where
202        D: serde::Deserializer<'de>,
203    {
204        struct TopicVisitor;
205
206        impl<'de> Visitor<'de> for TopicVisitor {
207            type Value = Topic<Hash>;
208            fn expecting(&self, formatter: &mut alloc::fmt::Formatter) -> alloc::fmt::Result {
209                write!(formatter, "Expect null/h256/[h256]")
210            }
211
212            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
213            where
214                E: serde::de::Error,
215            {
216                let topic = H256::from_str(v).map_err(serde::de::Error::custom)?;
217
218                Ok(Topic::This(topic))
219            }
220
221            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
222            where
223                A: serde::de::SeqAccess<'de>,
224            {
225                let mut topics = vec![];
226
227                while let Some(el) = seq.next_element::<&str>()? {
228                    let topic = H256::from_str(el).map_err(serde::de::Error::custom)?;
229
230                    topics.push(topic);
231                }
232
233                Ok(Topic::OneOf(topics))
234            }
235
236            fn visit_none<E>(self) -> Result<Self::Value, E>
237            where
238                E: serde::de::Error,
239            {
240                Ok(Topic::Any)
241            }
242
243            fn visit_unit<E>(self) -> Result<Self::Value, E>
244            where
245                E: serde::de::Error,
246            {
247                Ok(Topic::Any)
248            }
249        }
250
251        deserializer.deserialize_any(TopicVisitor {})
252    }
253}
254
255impl<T> ops::Index<usize> for Topic<T> {
256    type Output = T;
257
258    fn index(&self, index: usize) -> &Self::Output {
259        match *self {
260            Topic::Any | Topic::None => panic!("Topic unavailable"),
261            Topic::This(ref topic) => {
262                if index != 0 {
263                    panic!("Topic unavailable");
264                }
265                topic
266            }
267            Topic::OneOf(ref topics) => topics.index(index),
268        }
269    }
270}
271
272#[cfg(test)]
273mod tests {
274    use super::Topic;
275    #[cfg(feature = "serde")]
276    use super::TopicFilter;
277    #[cfg(not(feature = "std"))]
278    use crate::no_std_prelude::*;
279    #[cfg(feature = "serde")]
280    use crate::Hash;
281
282    #[cfg(feature = "serde")]
283    fn hash(s: &'static str) -> Hash {
284        s.parse().unwrap()
285    }
286
287    #[cfg(feature = "serde")]
288    #[test]
289    fn test_topic_filter_serialization() {
290        let expected = r#"["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b",null,["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b","0x0000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebccc"],null]"#;
291
292        let topic = TopicFilter {
293            topic0: Topic::This(hash(
294                "000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b",
295            )),
296            topic1: Topic::Any,
297            topic2: Topic::OneOf(vec![
298                hash("000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b"),
299                hash("0000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebccc"),
300            ]),
301            topic3: Topic::Any,
302        };
303
304        let topic_str = serde_json::to_string(&topic).unwrap();
305
306        assert_eq!(expected, &topic_str);
307
308        let expected_topic: TopicFilter = serde_json::from_str(&topic_str).unwrap();
309
310        assert_eq!(expected_topic, topic);
311    }
312
313    #[test]
314    fn test_topic_from() {
315        assert_eq!(Topic::Any as Topic<u64>, None.into());
316        assert_eq!(Topic::This(10u64), 10u64.into());
317        assert_eq!(Topic::OneOf(vec![10u64, 20]), vec![10u64, 20].into());
318    }
319
320    #[test]
321    fn test_topic_into_vec() {
322        let expected: Vec<u64> = vec![];
323        let is: Vec<u64> = (Topic::Any as Topic<u64>).into();
324        assert_eq!(expected, is);
325        let expected: Vec<u64> = vec![10];
326        let is: Vec<u64> = Topic::This(10u64).into();
327        assert_eq!(expected, is);
328        let expected: Vec<u64> = vec![10, 20];
329        let is: Vec<u64> = Topic::OneOf(vec![10u64, 20]).into();
330        assert_eq!(expected, is);
331    }
332
333    #[test]
334    fn test_topic_is_any() {
335        assert!((Topic::Any as Topic<u8>).is_any());
336        assert!(!Topic::OneOf(vec![10u64, 20]).is_any());
337        assert!(!Topic::This(10u64).is_any());
338    }
339
340    #[test]
341    fn test_topic_index() {
342        assert_eq!(Topic::OneOf(vec![10u64, 20])[0], 10);
343        assert_eq!(Topic::OneOf(vec![10u64, 20])[1], 20);
344        assert_eq!(Topic::This(10u64)[0], 10);
345    }
346
347    #[test]
348    #[should_panic(expected = "Topic unavailable")]
349    fn test_topic_index_panic() {
350        let _ = (Topic::Any as Topic<u8>)[0];
351    }
352
353    #[test]
354    #[should_panic(expected = "Topic unavailable")]
355    fn test_topic_index_panic2() {
356        assert_eq!(Topic::This(10u64)[1], 10);
357    }
358}