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>;
}