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}