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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
use void::Void;

use {Response, Scope, EventSet, SpawnError};


/// A trait that every state machine in the loop must implement
pub trait Machine: Sized {
    /// Context type for the state machine
    ///
    /// This is a container of the global state for the application
    type Context;
    /// Seed is piece of data that is needed to initialize the machine
    ///
    /// It needs Any because it's put into Box<Error> object when state machine
    /// is failed to create. Hopefully this is not huge limitation.
    ///
    /// Note: this is only used to create machines returned by this machine.
    /// So unless this machine processses accepting socket this should
    /// probably be Void.
    type Seed: Sized;

    /// Create a machine from some data
    ///
    /// The error should be rare enough so that Box<Error> overhead
    /// is negligible. Most errors here should be resource exhaustion, like
    /// there are no slots in Slab or system limit on epoll watches exceeded.
    ///
    /// Note: this method is used internally (by event loop) to create a
    /// socket from a Seed returned by this machine. This method should
    /// **not** be used to create machine by external code. Create a
    /// machine-specific `Type::new` method for the purpose.
    ///
    /// Note: we don't support spawning more state machines in create handler
    fn create(seed: Self::Seed, scope: &mut Scope<Self::Context>)
        -> Response<Self, Void>;

    /// Socket readiness notification
    fn ready(self, events: EventSet, scope: &mut Scope<Self::Context>)
        -> Response<Self, Self::Seed>;

    /// Called after spawn event
    ///
    /// This is mostly a continuation event. I.e. when you accept a socket
    /// and return a new state machine from `ready()`. You may wish to accept
    /// another socket right now. This is what `spawned` event is for.
    fn spawned(self, scope: &mut Scope<Self::Context>)
        -> Response<Self, Self::Seed>;

    /// Called instead of spawned, if there is no slab space
    ///
    /// For example, in `accept` handler you might want to put the thing
    /// into temporary storage, stop accepting and wait until slot is empty
    /// again.
    ///
    /// Note: it's useless to spawn from here if the failure was , it almost certainly will fail
    /// again, but may use a timeout
    fn spawn_error(self, _scope: &mut Scope<Self::Context>,
                   error: SpawnError<Self::Seed>)
        -> Response<Self, Self::Seed>
    {
        panic!("Error spawning state machine: {}", error);
    }

    /// Timeout happened
    fn timeout(self, scope: &mut Scope<Self::Context>)
        -> Response<Self, Self::Seed>;

    /// Message received
    ///
    /// Note the spurious wakeups are possible, because messages are
    /// asynchronous, and state machine is identified by token.
    /// Tokens are reused quickly.
    ///
    /// So never make this `unreachable!()` or `unimplemented!()`
    fn wakeup(self, scope: &mut Scope<Self::Context>)
        -> Response<Self, Self::Seed>;
}