1 module upromised.timer;
2 import deimos.libuv.uv : uv_timer_t, uv_handle_t, uv_loop_t, uv_timer_init, uv_timer_start, uv_timer_stop, uv_close, uv_timer_get_repeat;
3 import upromised.loop : Loop;
4 import upromised.promise : DelegatePromise, DelegatePromiseIterator, Promise, PromiseIterator;
5 import upromised.memory : getSelf, gcretain, gcrelease;
6 import upromised.uv : uvCheck;
7 import std.datetime : Duration;
8 import upromised : fatal;
9 
10 uv_handle_t* handle(ref uv_timer_t self) nothrow {
11     return cast(uv_handle_t*)&self;
12 }
13 
14 class Timer {
15 public:
16     uv_timer_t self;
17     DelegatePromise!void closePromise;
18     DelegatePromiseIterator!int startPromise;
19 
20     this(Loop loop) {
21         this(cast(uv_loop_t*)loop.inner());
22     }
23 
24     this(uv_loop_t* ctx) {
25         uv_timer_init(ctx, &self).uvCheck();
26         gcretain(this);
27     }
28 
29     Promise!void close() nothrow {
30         if (closePromise !is null) return closePromise;
31         closePromise = new DelegatePromise!void;
32         uv_close(self.handle, (selfSelf) nothrow {
33             auto self = getSelf!Timer(selfSelf);
34             gcrelease(self);
35             self.closePromise.resolve();
36         });
37         return closePromise;
38     }
39 
40     DelegatePromiseIterator!int start(Duration start, Duration repeat = Duration.init) nothrow {
41         import std.algorithm : swap;
42 
43         assert(startPromise is null);
44         startPromise = new DelegatePromiseIterator!int;
45         auto r = startPromise;
46         int err = uv_timer_start(&self, (selfSelf) nothrow {
47             auto self = getSelf!Timer(selfSelf);
48             self.startPromise.resolve(0).then((cont) {
49                 if (uv_timer_get_repeat(&self.self) == 0) {
50                     self.startPromise.resolve();
51                     self.startPromise = null;
52                 } else if (!cont) {
53                     uv_timer_stop(&self.self);
54                     self.startPromise = null;
55                 }
56             }).nothrow_();
57         }, start.total!"msecs", repeat.total!"msecs");
58         if (err.uvCheck(startPromise)) {
59             startPromise = null;
60         }
61         return r;
62     }
63 
64     static Promise!void once(uv_loop_t* ctx, Duration start = Duration.init) nothrow {
65         return Promise!void.resolved().then(() => new Timer(ctx)).then((timer) { 
66             return timer.start(start).each((a){}).finall(() => timer.close()).then((){});
67         });
68     }
69 }