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