1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#[macro_use(lift)]
extern crate carboxyl;

use carboxyl::{Signal, Stream};


pub trait Driver<Input> {
    type Output;

    fn output(&self) -> Self::Output;
    fn run(&mut self, input: Input);
}

#[derive(Clone)]
pub struct Communication<Context, Event> {
    pub context: Signal<Context>,
    pub events: Stream<Event>
}

pub struct Component<State, Update, View, Effect> {
    pub init: State,
    pub update: Update,
    pub view: View,
    pub effect: Effect
}

pub fn interpret<Context, Event, Action, Intent>(
        inputs: Communication<Context, Event>, intent: Intent)
        -> Communication<Context, Action>
    where Context: Clone + Send + Sync + 'static,
          Event: Clone + Send + Sync + 'static,
          Action: Clone + Send + Sync + 'static,
          Intent: Fn(Context, Event) -> Option<Action> + Send + Sync + 'static
{
    let events = inputs.context
        .snapshot(&inputs.events, intent)
        .filter_some();
    Communication {
        context: inputs.context,
        events: events
    }
}

pub fn start<Context, Event, State, Update, View, Effect, ViewOut, EffectOut>(
        app: Component<State, Update, View, Effect>,
        inputs: Communication<Context, Event>)
        -> Communication<ViewOut, EffectOut>
    where Event: Clone + Send + Sync + 'static,
          State: Clone + Send + Sync + 'static,
          Context: Clone + Send + Sync + 'static,
          ViewOut: Clone + Send + Sync + 'static,
          EffectOut: Clone + Send + Sync + 'static,
          Update: Fn(State, Event) -> State + Send + Sync + 'static,
          View: Fn(Context, State) -> ViewOut + Send + Sync + 'static,
          Effect: Fn(State, Event) -> Option<EffectOut> + Send + Sync + 'static
{
    let Component { init, update, view, effect } = app;
    let state = inputs.events.fold(init, update);
    Communication {
        context: lift!(view, &inputs.context, &state),
        events: state.snapshot(&inputs.events, effect).filter_some()
    }
}