1use 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#[derive(Debug, PartialEq, Default)]
20pub struct RawTopicFilter {
21 pub topic0: Topic<Token>,
23 pub topic1: Topic<Token>,
25 pub topic2: Topic<Token>,
27}
28
29#[derive(Debug, PartialEq, Default)]
31pub struct TopicFilter {
32 pub topic0: Topic<Hash>,
34 pub topic1: Topic<Hash>,
36 pub topic2: Topic<Hash>,
38 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#[derive(Debug, PartialEq)]
54pub enum Topic<T> {
55 Any,
57 OneOf(Vec<T>),
59 This(T),
61}
62
63impl<T> Topic<T> {
64 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 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) => {
131 let v: Vec<_> = vec.iter().map(|h| format!("0x{:x}", h)).collect();
132 v.serialize(serializer)
133 }
134 Topic::This(ref hash) => format!("0x{:x}", hash).serialize(serializer),
135 }
136 }
137}
138
139impl<T> ops::Index<usize> for Topic<T> {
140 type Output = T;
141
142 fn index(&self, index: usize) -> &Self::Output {
143 match *self {
144 Topic::Any => panic!("Topic unavailable"),
145 Topic::This(ref topic) => {
146 if index != 0 {
147 panic!("Topic unavailable");
148 }
149 topic
150 }
151 Topic::OneOf(ref topics) => topics.index(index),
152 }
153 }
154}
155
156#[cfg(test)]
157mod tests {
158 use super::Topic;
159 #[cfg(feature = "serde")]
160 use super::TopicFilter;
161 #[cfg(not(feature = "std"))]
162 use crate::no_std_prelude::*;
163 #[cfg(feature = "serde")]
164 use crate::Hash;
165
166 #[cfg(feature = "serde")]
167 fn hash(s: &'static str) -> Hash {
168 s.parse().unwrap()
169 }
170
171 #[cfg(feature = "serde")]
172 #[test]
173 fn test_topic_filter_serialization() {
174 let expected = r#"["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b",null,["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b","0x0000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebccc"],null]"#;
175
176 let topic = TopicFilter {
177 topic0: Topic::This(hash("000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b")),
178 topic1: Topic::Any,
179 topic2: Topic::OneOf(vec![
180 hash("000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b"),
181 hash("0000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebccc"),
182 ]),
183 topic3: Topic::Any,
184 };
185
186 let topic_str = serde_json::to_string(&topic).unwrap();
187 assert_eq!(expected, &topic_str);
188 }
189
190 #[test]
191 fn test_topic_from() {
192 assert_eq!(Topic::Any as Topic<u64>, None.into());
193 assert_eq!(Topic::This(10u64), 10u64.into());
194 assert_eq!(Topic::OneOf(vec![10u64, 20]), vec![10u64, 20].into());
195 }
196
197 #[test]
198 fn test_topic_into_vec() {
199 let expected: Vec<u64> = vec![];
200 let is: Vec<u64> = (Topic::Any as Topic<u64>).into();
201 assert_eq!(expected, is);
202 let expected: Vec<u64> = vec![10];
203 let is: Vec<u64> = Topic::This(10u64).into();
204 assert_eq!(expected, is);
205 let expected: Vec<u64> = vec![10, 20];
206 let is: Vec<u64> = Topic::OneOf(vec![10u64, 20]).into();
207 assert_eq!(expected, is);
208 }
209
210 #[test]
211 fn test_topic_is_any() {
212 assert!((Topic::Any as Topic<u8>).is_any());
213 assert!(!Topic::OneOf(vec![10u64, 20]).is_any());
214 assert!(!Topic::This(10u64).is_any());
215 }
216
217 #[test]
218 fn test_topic_index() {
219 assert_eq!(Topic::OneOf(vec![10u64, 20])[0], 10);
220 assert_eq!(Topic::OneOf(vec![10u64, 20])[1], 20);
221 assert_eq!(Topic::This(10u64)[0], 10);
222 }
223
224 #[test]
225 #[should_panic(expected = "Topic unavailable")]
226 fn test_topic_index_panic() {
227 let _ = (Topic::Any as Topic<u8>)[0];
228 }
229
230 #[test]
231 #[should_panic(expected = "Topic unavailable")]
232 fn test_topic_index_panic2() {
233 assert_eq!(Topic::This(10u64)[1], 10);
234 }
235}