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, Eq, 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, Eq)]
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) => 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}