1 module upromised.uv.work;
2 import deimos.libuv.uv;
3 import deimos.libuv._d;
4 import std.exception : enforce;
5 import upromised.memory : getSelf, gcretain, gcrelease;
6 import upromised.promise : DelegatePromise, Promisify, Promise;
7 import upromised.uv : uvCheck;
8 
9 private {
10     extern(C) void thread_attachThis() nothrow;
11 }
12 
13 class Work {
14 private:
15     uv_loop_t* ctx;
16     void delegate() work;
17     DelegatePromise!void result;
18     Promise!void.Value value;
19 
20 public:
21     uv_work_t self;
22 
23     this(uv_loop_t* ctx) nothrow {
24         this.ctx = ctx;
25     }
26 
27     Promise!void run(void delegate() work) nothrow {
28         import upromised.promise : promisifyCall;
29         
30         return Promise!void.resolved().then(() {
31             enforce(result is null, "Work already in progress");
32 
33             result = new DelegatePromise!void;
34             scope(failure) result = null;
35             this.work = work;
36 
37             auto err = uv_queue_work(ctx, &self, (self) nothrow {
38                 thread_attachThis();
39 
40                 promisifyCall(self.getSelf!Work().work)
41                 .then_((value) nothrow {
42                     self.getSelf!Work().value = value;
43                 });
44             }, (selfSelf, status) nothrow {
45                 auto self = selfSelf.getSelf!Work;
46                 auto result = self.result;
47                 self.result = null;
48                 result.resolve(self.value);
49             });
50             err.uvCheck();
51             
52             gcretain(this);
53             result.finall(() {
54                 gcrelease(this);
55             });
56 
57             return result;
58         });
59     }
60 
61     Promise!T run(T)(T delegate() cb) nothrow
62     if (is(Promisify!T == Promise!T) && !is(T == void))
63     {
64 
65         T r;
66         return run(() {
67             r = cb();
68         }).then(() => r);
69     }
70 }