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