1 /// Provides implementation of asynchronous timer. 2 module dpromise.utils.timer; 3 4 import core.time; 5 import dpromise.promise; 6 import deimos.libuv.uv, dpromise.internal.libuv; 7 8 9 /++ 10 Sleep in asynchronous while $(D dur). 11 12 If an error occurred, promise will be rejected. 13 14 Params: 15 dur = Duration of sleep. 16 17 See_Also: $(HTTP https://dlang.org/phobos/core_thread.html#.Thread.sleep, core.thread.Thread.sleep) 18 +/ 19 nothrow Promise!void sleepAsync(Duration dur) { 20 return promise!void((res, rej) { 21 nothrow void f(Exception e) { 22 e is null ? res() : rej(e); 23 } 24 25 sleepAsyncWithCallback(dur, &f); 26 }); 27 } 28 29 /// 30 @system unittest { 31 import dpromise.utils : runEventloop; 32 import std.datetime : Clock, SysTime, UTC; 33 34 auto startTime = Clock.currTime(UTC()); 35 36 sleepAsync(100.msecs).then({ 37 auto dur = Clock.currTime(UTC()) - startTime; 38 assert(dur + 4.msecs > 100.msecs); 39 assert(dur - 4.msecs < 100.msecs); 40 }); 41 42 runEventloop(); 43 } 44 45 46 /++ 47 Sleep in asynchronous while $(D dur) then calls the $(D callback) function. 48 49 If an error occurred, the $(D callback) function will be called with the error. 50 51 Params: 52 dur = Duration of sleep. 53 callback = a function called when operation finished or an error occurred. 54 +/ 55 nothrow @safe void sleepAsyncWithCallback(Duration dur, void delegate(Exception) nothrow callback) 56 in { 57 assert(callback !is null); 58 } body { 59 struct Data { 60 int err; 61 void delegate(Exception) nothrow callback; 62 } 63 64 extern(C) nothrow @trusted static void ret(uv_timer_t* tm) { 65 auto data = cast(Data*)tm.data; 66 auto callback = data.callback; 67 callback(factory(data.err)); 68 69 scope(exit) { 70 import core.memory : GC; 71 import core.stdc.stdlib : free; 72 GC.removeRoot(callback.ptr); 73 free(tm.data); 74 free(tm); 75 } 76 } 77 78 extern(C) nothrow @trusted static void onTimeout(uv_timer_t* tm) { 79 ret(tm); 80 } 81 82 () @trusted nothrow { 83 import core.time : Duration, TickDuration, to; 84 auto timeout = to!("msecs", ulong)(cast(TickDuration)dur); 85 86 import core.memory : GC; 87 auto timer = castMalloc!uv_timer_t; 88 uv_timer_init(localLoop, timer); 89 90 auto data = castMalloc!Data; 91 GC.addRoot(callback.ptr); 92 data.callback = callback; 93 timer.data = data; 94 95 data.err = uv_timer_start(timer, &onTimeout, timeout, 0); 96 if(data.err != 0) ret(timer); 97 }(); 98 } 99 /// 100 @safe unittest { 101 import dpromise.utils : runEventloop; 102 import std.datetime : Clock, UTC; 103 104 auto startTime = Clock.currTime(UTC()); 105 sleepAsyncWithCallback(100.msecs, (e) nothrow { 106 try { 107 auto dur = Clock.currTime(UTC()) - startTime; 108 assert(dur + 4.msecs > 100.msecs); 109 assert(dur - 4.msecs < 100.msecs); 110 } catch(Exception e) {} 111 }); 112 113 runEventloop(); 114 }