rust_apex/
lib.rs

1extern crate serde;
2extern crate serde_json;
3#[macro_use]
4extern crate serde_derive;
5extern crate failure;
6
7use std::io::stdin;
8
9use failure::Error;
10use serde::{Serialize, Deserialize};
11use serde_json::{from_str, to_string};
12
13use types::{Input, Output};
14
15pub use types::Context;
16
17mod types;
18mod macros;
19
20pub trait Handler<I: for<'de> Deserialize<'de>, O: Serialize, E: Into<Error>> {
21    fn handle(&self, I, Context) -> Result<O, E>;
22}
23
24impl<I, O, E, F> Handler<I, O, E> for F
25where
26    I: for<'de> Deserialize<'de>,
27    O: Serialize,
28    E: Into<Error>,
29    F: Fn(I, Context) -> Result<O, E>,
30{
31    fn handle(&self, ipt: I, ctx: Context) -> Result<O, E> {
32        self(ipt, ctx)
33    }
34}
35
36pub fn run<I, O, E, H>(h: H)
37where
38    I: for<'de> Deserialize<'de>,
39    O: Serialize,
40    E: Into<Error>,
41    H: Handler<I, O, E>,
42{
43    let mut buf = String::new();
44    loop {
45
46        // use `from_reader(stdin())` here is not correct.
47        if let Err(e) = stdin().read_line(&mut buf) {
48            return_error::<O, _, _>(None, e);
49            break;
50        }
51        let i: Result<Input<I>, _> = from_str(&buf);
52
53        match i {
54            Ok(ipt) => {
55                match h.handle(ipt.event, ipt.context) {
56                    Ok(r) => return_success(ipt.id, r),
57                    Err(e) => return_error::<O, _, _>(ipt.id, e),
58                }
59            }
60            Err(e) => return_error::<O, _, _>(None, e),
61        }
62
63        buf.clear();
64    }
65}
66
67fn return_error<O: Serialize, E: Into<Error>, K: Into<Option<String>>>(id: K, e: E) {
68    let id = id.into();
69
70    let s = to_string(&Output::Error::<O> {
71        id: id,
72        error: format!("{}", e.into()),
73    }).unwrap();
74    println!("{}", s);
75}
76
77fn return_success<O: Serialize>(id: String, r: O) {
78    let s = to_string(&Output::Value { id: id, value: r }).unwrap();
79    println!("{}", s);
80}