rotor/
machine.rs

1use void::Void;
2
3use {Response, Scope, EventSet, SpawnError};
4
5
6/// A trait that every state machine in the loop must implement
7pub trait Machine: Sized {
8    /// Context type for the state machine
9    ///
10    /// This is a container of the global state for the application
11    type Context;
12    /// Seed is piece of data that is needed to initialize the machine
13    ///
14    /// It needs Any because it's put into Box<Error> object when state machine
15    /// is failed to create. Hopefully this is not huge limitation.
16    ///
17    /// Note: this is only used to create machines returned by this machine.
18    /// So unless this machine processses accepting socket this should
19    /// probably be Void.
20    type Seed: Sized;
21
22    /// Create a machine from some data
23    ///
24    /// The error should be rare enough so that Box<Error> overhead
25    /// is negligible. Most errors here should be resource exhaustion, like
26    /// there are no slots in Slab or system limit on epoll watches exceeded.
27    ///
28    /// Note: this method is used internally (by event loop) to create a
29    /// socket from a Seed returned by this machine. This method should
30    /// **not** be used to create machine by external code. Create a
31    /// machine-specific `Type::new` method for the purpose.
32    ///
33    /// Note: we don't support spawning more state machines in create handler
34    fn create(seed: Self::Seed, scope: &mut Scope<Self::Context>)
35        -> Response<Self, Void>;
36
37    /// Socket readiness notification
38    fn ready(self, events: EventSet, scope: &mut Scope<Self::Context>)
39        -> Response<Self, Self::Seed>;
40
41    /// Called after spawn event
42    ///
43    /// This is mostly a continuation event. I.e. when you accept a socket
44    /// and return a new state machine from `ready()`. You may wish to accept
45    /// another socket right now. This is what `spawned` event is for.
46    fn spawned(self, scope: &mut Scope<Self::Context>)
47        -> Response<Self, Self::Seed>;
48
49    /// Called instead of spawned, if there is no slab space
50    ///
51    /// For example, in `accept` handler you might want to put the thing
52    /// into temporary storage, stop accepting and wait until slot is empty
53    /// again.
54    ///
55    /// Note: it's useless to spawn from here if the failure was , it almost certainly will fail
56    /// again, but may use a timeout
57    fn spawn_error(self, _scope: &mut Scope<Self::Context>,
58                   error: SpawnError<Self::Seed>)
59        -> Response<Self, Self::Seed>
60    {
61        panic!("Error spawning state machine: {}", error);
62    }
63
64    /// Timeout happened
65    fn timeout(self, scope: &mut Scope<Self::Context>)
66        -> Response<Self, Self::Seed>;
67
68    /// Message received
69    ///
70    /// Note the spurious wakeups are possible, because messages are
71    /// asynchronous, and state machine is identified by token.
72    /// Tokens are reused quickly.
73    ///
74    /// So never make this `unreachable!()` or `unimplemented!()`
75    fn wakeup(self, scope: &mut Scope<Self::Context>)
76        -> Response<Self, Self::Seed>;
77}