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
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
use std::io;
use std::ops::{Deref, DerefMut};

use mio::{Token, Sender};
use time::{Timespec};

use handler::Notify;
use loop_api::LoopApi;
use loop_time::{estimate_timespec};
use notify::create_notifier;
use {Notifier, Time};
use {Evented, EventSet, PollOpt, Timeout, TimerError};

/// The structure passed to every action handler
///
/// Scope is used for the following purposes:
///
/// 1. Register/deregister sockets in the event loop
/// 2. Register timeouts
/// 3. Create a special `Notifier` object to wakeup sibling state machines
/// 4. Access to global state of the loop (Context)
///
/// All methods here operate on **enclosed state machine**, which means the
/// state machine that was called with this scope. Or in other words the
/// state machine that actually performs an action.
///
/// The only way to notify another state machine is to create a `notifier()`
/// (the `Notifier` is only able to wakeup this state machine still), transfer
/// it to another state machine (for example putting it into the context)
/// and call `Notifier::wakeup()`.
///
/// The structure derefs to the context (``C``) for convenience
pub struct Scope<'a, C:Sized+'a>{
    token: Token,
    ctx: &'a mut C,
    channel: &'a mut Sender<Notify>,
    loop_api: &'a mut LoopApi,
    time: Time,
}

/// This is a structure that works similarly to Scope, but doesn't
/// have a context
///
/// The primary (and probably the only) use case for the `EarlyScope` is to
/// allow to create a state machine before context has been intialized. This
/// is useful if you want to put a `Notifier` of the FSM to a context itself.
pub struct EarlyScope<'a> {
    token: Token,
    channel: &'a mut Sender<Notify>,
    loop_api: &'a mut LoopApi,
}

/// A common part of `Scope` and `EarlyScope`
///
/// For most cases `Scope` scope should be used directly. The trait is here
/// so you can create a constructor for state machine that is generic over
/// type of scope used.
pub trait GenericScope {
    fn register(&mut self, io: &Evented, interest: EventSet, opt: PollOpt)
        -> io::Result<()>;
    fn reregister(&mut self, io: &Evented,
        interest: EventSet, opt: PollOpt)
        -> io::Result<()>;
    fn deregister(&mut self, io: &Evented) -> io::Result<()>;

    /// Add timeout
    ///
    /// This method is **deprecated** use return value of your state machine's
    /// action to set a timeout
    fn timeout_ms(&mut self, delay: u64) -> Result<Timeout, TimerError>;
    /// Clear timeout
    ///
    /// This method is **deprecated** (with timeout_ms) use return value of
    /// your state machine's action to change a timeout
    fn clear_timeout(&mut self, token: Timeout) -> bool;

    /// Returns an object that can be used to wake up the enclosed
    /// state machine
    fn notifier(&mut self) -> Notifier;

    /// Time of the current loop iteration
    ///
    /// This is a time that needs to be used for timeouts. It's cheap to use
    fn now(&self) -> Time;

    /// Returns the Timespec that corresponds to the Time in this loop
    ///
    /// Note: this is an estimate, because we use *monotonic* time under the
    /// hood, but `Timespec` is a subject for adjustments of the system clock.
    ///
    /// I.e. it is fine to use this time to present it to the user, but it's
    /// wrong to rely on it in code.
    fn estimate_timespec(&self, time: Time) -> Timespec {
        estimate_timespec(self.now(), time)
    }
}

impl<'a, C:Sized+'a> Scope<'a, C> {

    pub fn register(&mut self, io: &Evented, interest: EventSet, opt: PollOpt)
        -> io::Result<()>
    {
        self.loop_api.register(io, self.token, interest, opt)
    }

    pub fn reregister(&mut self, io: &Evented,
        interest: EventSet, opt: PollOpt)
        -> io::Result<()>
    {
        self.loop_api.reregister(io, self.token, interest, opt)
    }

    pub fn deregister(&mut self, io: &Evented) -> io::Result<()>
    {
        self.loop_api.deregister(io)
    }

    /// Add timeout
    ///
    /// This method is **deprecated** use return value of your state machine's
    /// action to set a timeout
    pub fn timeout_ms(&mut self, delay: u64) -> Result<Timeout, TimerError>
    {
        self.loop_api.timeout_ms(self.token, delay)
    }

    /// Clear timeout
    ///
    /// This method is **deprecated** (with timeout_ms) use return value of
    /// your state machine's action to change a timeout
    pub fn clear_timeout(&mut self, token: Timeout) -> bool
    {
        self.loop_api.clear_timeout(token)
    }

    /// Create a `Notifier` that may be used to `wakeup` enclosed state machine
    pub fn notifier(&mut self) -> Notifier {
        create_notifier(self.token, self.channel)
    }

    /// Shutdown the event loop
    pub fn shutdown_loop(&mut self) {
        self.loop_api.shutdown()
    }

    /// Time of the current loop iteration
    ///
    /// This is a time that needs to be used for timeouts. It's cheap to use
    pub fn now(&self) -> Time {
        self.time
    }

    /// Returns the Timespec that corresponds to the Time in this loop
    ///
    /// Note: this is an estimate, because we use *monotonic* time under the
    /// hood, but `Timespec` is a subject for adjustments of the system clock.
    ///
    /// I.e. it is fine to use this time to present it to the user, but it's
    /// wrong to rely on it in code.
    pub fn estimate_timespec(&self, time: Time) -> Timespec {
        estimate_timespec(self.now(), time)
    }
}

impl<'a, C:Sized+'a> GenericScope for Scope<'a, C> {

    fn register(&mut self, io: &Evented, interest: EventSet, opt: PollOpt)
        -> io::Result<()>
    {
        self.register(io, interest, opt)
    }

    fn reregister(&mut self, io: &Evented,
        interest: EventSet, opt: PollOpt)
        -> io::Result<()>
    {
        self.reregister(io, interest, opt)
    }

    fn deregister(&mut self, io: &Evented) -> io::Result<()>
    {
        self.deregister(io)
    }

    /// Add timeout
    ///
    /// This method is **deprecated** use return value of your state machine's
    /// action to set a timeout
    fn timeout_ms(&mut self, delay: u64) -> Result<Timeout, TimerError>
    {
        self.timeout_ms(delay)
    }

    /// Clear timeout
    ///
    /// This method is **deprecated** (with timeout_ms) use return value of
    /// your state machine's action to change a timeout
    fn clear_timeout(&mut self, token: Timeout) -> bool
    {
        self.clear_timeout(token)
    }

    /// Create a `Notifier` that may be used to `wakeup` enclosed state machine
    fn notifier(&mut self) -> Notifier {
        self.notifier()
    }

    /// Time of the current loop iteration
    ///
    /// This is a time that needs to be used for timeouts. It's cheap to use
    fn now(&self) -> Time {
        self.time
    }
}

impl<'a, C> Deref for Scope<'a, C> {
    type Target = C;
    fn deref(&self) -> &C {
        self.ctx
    }
}

impl<'a, C> DerefMut for Scope<'a, C> {
    fn deref_mut(&mut self) -> &mut C {
        self.ctx
    }
}

impl<'a> EarlyScope<'a> {

    pub fn register(&mut self, io: &Evented, interest: EventSet, opt: PollOpt)
        -> io::Result<()>
    {
        self.loop_api.register(io, self.token, interest, opt)
    }

    pub fn reregister(&mut self, io: &Evented,
        interest: EventSet, opt: PollOpt)
        -> io::Result<()>
    {
        self.loop_api.reregister(io, self.token, interest, opt)
    }

    pub fn deregister(&mut self, io: &Evented) -> io::Result<()>
    {
        self.loop_api.deregister(io)
    }

    /// Add timeout
    ///
    /// This method is **deprecated** use return value of your state machine's
    /// action to set a timeout
    pub fn timeout_ms(&mut self, delay: u64) -> Result<Timeout, TimerError>
    {
        self.loop_api.timeout_ms(self.token, delay)
    }

    /// Clear timeout
    ///
    /// This method is **deprecated** (with timeout_ms) use return value of
    /// your state machine's action to change a timeout
    pub fn clear_timeout(&mut self, token: Timeout) -> bool
    {
        self.loop_api.clear_timeout(token)
    }

    /// Create a `Notifier` that may be used to `wakeup` enclosed state machine
    pub fn notifier(&mut self) -> Notifier {
        create_notifier(self.token, self.channel)
    }

    /// Time of the current loop iteration
    ///
    /// This is a time that needs to be used for timeouts. It's cheap to use
    pub fn now(&self) -> Time {
        // Early scope is only used when creating a context. It's definitely
        // at the start of the things. But we may review this in future.
        Time::zero()
    }

    /// Returns the Timespec that corresponds to the Time in this loop
    ///
    /// Note: this is an estimate, because we use *monotonic* time under the
    /// hood, but `Timespec` is a subject for adjustments of the system clock.
    ///
    /// I.e. it is fine to use this time to present it to the user, but it's
    /// wrong to rely on it in code.
    pub fn estimate_timespec(&self, time: Time) -> Timespec {
        estimate_timespec(self.now(), time)
    }
}

impl<'a> GenericScope for EarlyScope<'a> {

    fn register(&mut self, io: &Evented, interest: EventSet, opt: PollOpt)
        -> io::Result<()>
    {
        self.register(io, interest, opt)
    }

    fn reregister(&mut self, io: &Evented,
        interest: EventSet, opt: PollOpt)
        -> io::Result<()>
    {
        self.reregister(io, interest, opt)
    }

    fn deregister(&mut self, io: &Evented) -> io::Result<()>
    {
        self.deregister(io)
    }

    /// Add timeout
    ///
    /// This method is **deprecated** use return value of your state machine's
    /// action to set a timeout
    fn timeout_ms(&mut self, delay: u64) -> Result<Timeout, TimerError>
    {
        self.timeout_ms(delay)
    }

    /// Clear timeout
    ///
    /// This method is **deprecated** (with timeout_ms) use return value of
    /// your state machine's action to change a timeout
    fn clear_timeout(&mut self, token: Timeout) -> bool
    {
        self.clear_timeout(token)
    }

    /// Create a `Notifier` that may be used to `wakeup` enclosed state machine
    fn notifier(&mut self) -> Notifier {
        self.notifier()
    }
    /// Time of the current loop iteration
    ///
    /// This is a time that needs to be used for timeouts. It's cheap to use
    fn now(&self) -> Time {
        // Early scope is only used when creating a context. It's definitely
        // at the start of the things. But we may review this in future.
        Time::zero()
    }
}

#[doc(hidden)]
pub fn scope<'x, C, L:LoopApi>(time: Time, token: Token, ctx: &'x mut C,
    channel: &'x mut Sender<Notify>, loop_api: &'x mut L)
    -> Scope<'x, C>
{
    Scope {
        token: token,
        ctx: ctx,
        channel: channel,
        loop_api: loop_api,
        time: time,
    }
}

#[doc(hidden)]
pub fn early_scope<'x, L:LoopApi>(token: Token,
    channel: &'x mut Sender<Notify>, loop_api: &'x mut L)
    -> EarlyScope<'x>
{
    EarlyScope {
        token: token,
        channel: channel,
        loop_api: loop_api,
    }
}