1use errors::*;
2use rustc_serialize as S;
3use regex as R;
4
5pub struct Decoder<'a> {
6 captures: R::Captures<'a>,
7 stack: Vec<String>,
8}
9
10impl<'a> Decoder<'a> {
11 pub fn new(captures: R::Captures<'a>) -> Decoder<'a> {
12 Decoder {
13 captures: captures,
14 stack: vec![],
15 }
16 }
17}
18
19macro_rules! read_primitive {
20 ($name:ident, $ty:ident) => {
21 fn $name(&mut self) -> Result<$ty> {
22 match self.stack.pop() {
23 None => Err("missing value".into()),
24 Some(value) => value.parse().chain_err(|| "failed to decode primitive")
25 }
26 }
27 }
28}
29
30impl<'a> S::Decoder for Decoder<'a> {
31 type Error = Error;
32
33 fn read_nil(&mut self) -> Result<()> {
34 unimplemented!();
35 }
36
37 read_primitive! { read_usize, usize }
38 read_primitive! { read_u64, u64 }
39 read_primitive! { read_u32, u32 }
40 read_primitive! { read_u16, u16 }
41 read_primitive! { read_u8, u8 }
42
43 read_primitive! { read_isize, isize }
44 read_primitive! { read_i64, i64 }
45 read_primitive! { read_i32, i32 }
46 read_primitive! { read_i16, i16 }
47 read_primitive! { read_i8, i8 }
48
49 read_primitive! { read_f64, f64 }
50 read_primitive! { read_f32, f32 }
51
52 fn read_bool(&mut self) -> Result<bool> {
53 unimplemented!();
54 }
55
56 fn read_char(&mut self) -> Result<char> {
57 match self.stack.pop() {
58 None => Err("missing value".into()),
59 Some(value) => {
60 let mut chars = value.chars();
61
62 let c = match chars.next() {
63 None => return Err("missing value".into()),
64 Some(c) => c,
65 };
66
67 match chars.next() {
68 None => Ok(c),
69 Some(_) => Err("extra characters found".into()),
70 }
71 }
72 }
73 }
74
75 fn read_str(&mut self) -> Result<String> {
76 match self.stack.pop() {
77 None => Err("missing value".into()),
78 Some(value) => Ok(value.into())
79 }
80 }
81
82 fn read_enum<T, F>(&mut self, _: &str, f: F) -> Result<T> where F: FnOnce(&mut Self) -> Result<T> {
83 f(self)
84 }
85
86 fn read_enum_variant<T, F>(&mut self, names: &[&str], mut f: F) -> Result<T> where F: FnMut(&mut Self, usize) -> Result<T> {
87 let name = match self.stack.pop() {
88 None => return Err("missing value".into()),
89 Some(name) => name,
90 };
91
92 let idx = match names.iter().position(|n| *n == name) {
93 Some(idx) => idx,
94 None => return Err(format!("unknown variant {}", name).into())
95 };
96 f(self, idx)
97 }
98
99 fn read_enum_variant_arg<T, F>(&mut self, _: usize, f: F) -> Result<T> where F: FnOnce(&mut Self) -> Result<T> {
100 f(self)
101 }
102
103 fn read_enum_struct_variant<T, F>(&mut self, names: &[&str], f: F) -> Result<T> where F: FnMut(&mut Self, usize) -> Result<T> {
104 self.read_enum_variant(names, f)
105 }
106
107 fn read_enum_struct_variant_field<T, F>(&mut self, _: &str, f_idx: usize, f: F) -> Result<T> where F: FnOnce(&mut Self) -> Result<T> {
108 self.read_enum_variant_arg(f_idx, f)
109 }
110
111 fn read_struct<T, F>(&mut self, _: &str, _: usize, f: F) -> Result<T> where F: FnOnce(&mut Self) -> Result<T> {
112 f(self)
113 }
114
115 fn read_struct_field<T, F>(&mut self, f_name: &str, _: usize, f: F) -> Result<T> where F: FnOnce(&mut Self) -> Result<T> {
116 match self.captures.name(f_name) {
117 None => Err("missing field name".into()),
118 Some(val) => {
119 self.stack.push(val.to_string());
120 f(self)
121 }
122 }
123 }
124
125 fn read_tuple<T, F>(&mut self, _: usize, f: F) -> Result<T> where F: FnOnce(&mut Self) -> Result<T> {
126 f(self)
127 }
128
129 fn read_tuple_arg<T, F>(&mut self, a_idx: usize, f: F) -> Result<T> where F: FnOnce(&mut Self) -> Result<T> {
130 match self.captures.at(a_idx + 1) {
132 None => Err("missing tuple arg".into()),
133 Some(val) => {
134 self.stack.push(val.to_string());
135 f(self)
136 }
137 }
138 }
139
140 fn read_tuple_struct<T, F>(&mut self, _: &str, len: usize, f: F) -> Result<T> where F: FnOnce(&mut Self) -> Result<T> {
141 self.read_tuple(len, f)
142 }
143
144 fn read_tuple_struct_arg<T, F>(&mut self, a_idx: usize, f: F) -> Result<T> where F: FnOnce(&mut Self) -> Result<T> {
145 self.read_tuple_arg(a_idx, f)
146 }
147
148 fn read_option<T, F>(&mut self, mut f: F) -> Result<T> where F: FnMut(&mut Self, bool) -> Result<T> {
149 let value = self.stack.pop();
150
151 match value {
152 None => f(self, false),
153 Some(value) => {
154 self.stack.push(value);
155 f(self, true)
156 }
157 }
158 }
159
160 fn read_seq<T, F>(&mut self, f: F) -> Result<T> where F: FnOnce(&mut Self, usize) -> Result<T> {
161 let mut temp = vec![];
162 for val in self.captures.iter().skip(1) {
163 temp.push(val.unwrap().to_string());
164 }
165 temp.reverse();
166 let len = temp.len();
167 self.stack.extend(temp);
168 f(self, len)
169 }
170
171 fn read_seq_elt<T, F>(&mut self, _: usize, f: F) -> Result<T> where F: FnOnce(&mut Self) -> Result<T> {
172 f(self)
173 }
174
175 fn read_map<T, F>(&mut self, f: F) -> Result<T> where F: FnOnce(&mut Self, usize) -> Result<T> {
176 let len = self.captures.len() - 1;
177
178 for (key, value) in self.captures.iter_named() {
179 self.stack.push(value.unwrap().to_string());
180 self.stack.push(key.to_string());
181 }
182
183 f(self, len)
184 }
185
186 fn read_map_elt_key<T, F>(&mut self, _: usize, f: F) -> Result<T> where F: FnOnce(&mut Self) -> Result<T> {
187 f(self)
188 }
189
190 fn read_map_elt_val<T, F>(&mut self, _: usize, f: F) -> Result<T> where F: FnOnce(&mut Self) -> Result<T> {
191 f(self)
192 }
193
194 fn error(&mut self, err: &str) -> Self::Error {
195 err.into()
196 }
197}
198
199pub fn decode<T: S::Decodable>(regex: &R::Regex, string: &str) -> Result<T> {
200 match regex.captures(string) {
201 None => Err("regex failed to match against text".into()),
202 Some(captures) => {
203 let mut decoder = Decoder::new(captures);
204 S::Decodable::decode(&mut decoder)
205 }
206 }
207}
208
209#[cfg(test)]
210mod tests {
211 use std::collections::HashMap;
212 use regex as R;
213 use super::*;
214
215 #[test]
216 fn decode_struct_with_strings() {
217 #[derive(RustcDecodable)]
218 struct Capture {
219 pub title: String,
220 pub year: String,
221 }
222
223 let re = R::Regex::new(r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)")
224 .unwrap();
225 let text = "Not my favorite movie: 'Citizen Kane' (1941).";
226
227 let val = decode::<Capture>(&re, &text).unwrap();
228
229 assert_eq!(&val.title, "Citizen Kane");
230 assert_eq!(&val.year, "1941");
231 }
232
233 #[test]
234 fn decode_struct_with_usize() {
235 #[derive(RustcDecodable)]
236 struct Capture {
237 pub title: String,
238 pub year: usize,
239 }
240
241 let re = R::Regex::new(r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)")
242 .unwrap();
243 let text = "Not my favorite movie: 'Citizen Kane' (1941).";
244
245 let val = decode::<Capture>(&re, &text).unwrap();
246
247 assert_eq!(&val.title, "Citizen Kane");
248 assert_eq!(val.year, 1941);
249 }
250
251 #[test]
252 fn decode_struct_with_u64() {
253 #[derive(RustcDecodable)]
254 struct Capture {
255 pub title: String,
256 pub year: u64,
257 }
258
259 let re = R::Regex::new(r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)")
260 .unwrap();
261 let text = "Not my favorite movie: 'Citizen Kane' (1941).";
262
263 let val = decode::<Capture>(&re, &text).unwrap();
264
265 assert_eq!(&val.title, "Citizen Kane");
266 assert_eq!(val.year, 1941);
267 }
268
269 #[test]
270 fn decode_struct_with_u32() {
271 #[derive(RustcDecodable)]
272 struct Capture {
273 pub title: String,
274 pub year: u32,
275 }
276
277 let re = R::Regex::new(r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)")
278 .unwrap();
279 let text = "Not my favorite movie: 'Citizen Kane' (1941).";
280
281 let val = decode::<Capture>(&re, &text).unwrap();
282
283 assert_eq!(&val.title, "Citizen Kane");
284 assert_eq!(val.year, 1941);
285 }
286
287 #[test]
288 fn decode_struct_with_u16() {
289 #[derive(RustcDecodable)]
290 struct Capture {
291 pub title: String,
292 pub year: u16,
293 }
294
295 let re = R::Regex::new(r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)")
296 .unwrap();
297 let text = "Not my favorite movie: 'Citizen Kane' (1941).";
298
299 let val = decode::<Capture>(&re, &text).unwrap();
300
301 assert_eq!(&val.title, "Citizen Kane");
302 assert_eq!(val.year, 1941);
303 }
304
305 #[test]
306 #[should_panic]
307 fn decode_struct_with_u8_too_large() {
308 #[derive(RustcDecodable)]
309 struct Capture {
310 pub title: String,
311 pub year: u8,
312 }
313
314 let re = R::Regex::new(r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)")
315 .unwrap();
316 let text = "Not my favorite movie: 'Citizen Kane' (1941).";
317
318 decode::<Capture>(&re, &text).unwrap();
320 }
321
322 #[test]
323 fn decode_struct_with_u8() {
324 #[derive(RustcDecodable)]
325 struct Capture {
326 pub title: String,
327 pub year: u8,
328 }
329
330 let re = R::Regex::new(r"'(?P<title>[^']+)'\s+\((?P<year>\d{2})\)")
331 .unwrap();
332 let text = "Not my favorite movie: 'Citizen Kane' (41).";
333
334 let val = decode::<Capture>(&re, &text).unwrap();
335
336 assert_eq!(&val.title, "Citizen Kane");
337 assert_eq!(val.year, 41);
338 }
339
340 #[test]
341 #[should_panic]
342 fn decode_struct_with_char_too_large() {
343 #[derive(RustcDecodable)]
344 struct Capture {
345 pub title: char,
346 pub year: usize,
347 }
348
349 let re = R::Regex::new(r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)")
350 .unwrap();
351 let text = "Not my favorite movie: 'Citizen Kane' (1941).";
352
353 decode::<Capture>(&re, &text).unwrap();
355 }
356
357 #[test]
358 fn decode_struct_with_char() {
359 #[derive(RustcDecodable)]
360 struct Capture {
361 pub title: char,
362 pub year: usize,
363 }
364
365 let re = R::Regex::new(r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)")
366 .unwrap();
367 let text = "Not my favorite movie: 'C' (1941).";
368
369 let val = decode::<Capture>(&re, &text).unwrap();
370
371 assert_eq!(val.title, 'C');
372 assert_eq!(val.year, 1941);
373 }
374
375 #[test]
376 fn decode_struct_with_option() {
377 #[derive(RustcDecodable)]
378 struct Capture {
379 pub title: String,
380 pub year: Option<usize>,
381 }
382
383 let re = R::Regex::new(r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)")
384 .unwrap();
385 let text = "Not my favorite movie: 'Citizen Kane' (1941).";
386
387 let val = decode::<Capture>(&re, &text).unwrap();
388
389 assert_eq!(val.title, "Citizen Kane");
390 assert_eq!(val.year.is_some(), true);
391 assert_eq!(val.year.unwrap(), 1941);
392 }
393
394 #[test]
395 fn decode_tuple() {
396 let re = R::Regex::new(r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)")
397 .unwrap();
398 let text = "Not my favorite movie: 'Citizen Kane' (1941).";
399
400 let (title, year) = decode::<(String, usize)>(&re, &text).unwrap();
401
402 assert_eq!(title, "Citizen Kane");
403 assert_eq!(year, 1941);
404 }
405
406 #[test]
407 fn decode_vec_string() {
408 let re = R::Regex::new(r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)")
409 .unwrap();
410 let text = "Not my favorite movie: 'Citizen Kane' (1941).";
411
412 let val = decode::<Vec<String>>(&re, &text).unwrap();
413
414 assert_eq!(val[0], "Citizen Kane");
415 assert_eq!(val[1], "1941");
416 }
417
418 #[test]
419 fn decode_hashmap() {
420 let re = R::Regex::new(r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)")
421 .unwrap();
422 let text = "Not my favorite movie: 'Citizen Kane' (1941).";
423
424 let val = decode::<HashMap<String, String>>(&re, &text).unwrap();
425
426 assert_eq!(val.get("title").unwrap(), "Citizen Kane");
427 assert_eq!(val.get("year").unwrap(), "1941");
428 }
429
430 #[test]
431 fn decode_struct_enum() {
432 #[derive(Debug, RustcDecodable, PartialEq)]
433 enum Blah {
434 Foo,
435 Bar,
436 }
437
438 #[derive(RustcDecodable)]
439 struct Capture {
440 pub title: Blah,
441 pub year: usize,
442 }
443
444 let re = R::Regex::new(r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)")
445 .unwrap();
446 let text = "Not my favorite movie: 'Foo' (1941).";
447
448 let val = decode::<Capture>(&re, &text).unwrap();
449
450 assert_eq!(val.title, Blah::Foo);
451 assert_eq!(val.year, 1941);
452 }
453}