1 /*
2  * Kiss - A refined core library for D programming language.
3  *
4  * Copyright (C) 2015-2018  Shanghai Putao Technology Co., Ltd
5  *
6  * Developer: HuntLabs.cn
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11  
12 module kiss.event.task;
13 
14 import std.traits;
15 import std.experimental.allocator;
16 import std.variant;
17 import core.atomic;
18 import std.exception;
19 
20 ReturnType!F run(F, Args...)(F fpOrDelegate, ref Args args) {
21     return fpOrDelegate(args);
22 }
23 
24 enum TaskStatus : ubyte {
25     LDLE = 0x00,
26     Runing = 0x01,
27     Finsh = 0x02,
28     InVaild = 0x03,
29 }
30 
31 @trusted class AbstractTask {
32     alias TaskFun = bool function(AbstractTask);
33     alias FinishCall = void delegate(AbstractTask) nothrow;
34 
35     final void job() nothrow {
36         if (atomicLoad(_status) != TaskStatus.LDLE)
37             return;
38         atomicStore(_status, TaskStatus.Runing);
39         scope (failure)
40             atomicStore(_status, TaskStatus.InVaild);
41         bool rv = false;
42         if (_runTask){
43             _e = collectException(_runTask(this),rv);
44         }
45         if (rv)
46             atomicStore(_status, TaskStatus.Finsh);
47         else
48             atomicStore(_status, TaskStatus.InVaild);
49         if(_finish)
50             _finish(this);
51     }
52 
53     final bool rest() {
54         if (isRuning)
55             return false;
56         atomicStore(_status, TaskStatus.LDLE);
57         return true;
58     }
59 
60     final @property TaskStatus status() {
61         return atomicLoad(_status);
62     }
63 
64     pragma(inline, true) final bool isRuning() {
65         return (atomicLoad(_status) == TaskStatus.Runing);
66     }
67 
68     @property Variant returnValue(){return _rvalue;}
69     @property Exception throwExecption(){return _e;}
70 
71     @property FinishCall finishedCall(){return _finish;}
72     @property void finishedCall(FinishCall finish){_finish = finish;}
73 protected:
74     this(TaskFun fun) {
75         _runTask = fun;
76     }
77  
78 private: 
79     TaskFun _runTask;
80     shared TaskStatus _status = TaskStatus.LDLE;
81 private: //return
82     Exception _e;
83     Variant _rvalue;
84     FinishCall _finish;
85 private: // Use in queue
86     AbstractTask next;
87 }
88 
89 @trusted final class Task(alias fun, Args...) : AbstractTask {
90     static if (Args.length > 0) {
91         this(Args args) {
92             _args = args;
93             super(&impl);
94         }
95 
96         Args _args;
97     } else {
98         this() {
99             super(&impl);
100         }
101 
102         alias _args = void;
103     }
104 
105     static bool impl(AbstractTask myTask) {
106         auto myCastedTask = cast(typeof(this)) myTask;
107         if (myCastedTask is null)
108             return false;
109         alias RType = typeof(fun(_args));
110         static if (is(RType == void))
111             fun(myCastedTask._args);
112         else
113             myCastedTask._rvalue = fun(myCastedTask._args);
114         return true;
115     }
116 }
117 
118 @trusted auto makeTask(alias fun, Alloc, Args...)(Alloc alloc, Args args) {
119     return make!(Task!(fun, Args))(alloc, args);
120 }
121 
122 @trusted auto makeTask(F, Alloc, Args...)(Alloc alloc, F delegateOrFp, Args args) if (
123         is(typeof(delegateOrFp(args)))) {
124     return make!(Task!(run, F, Args))(alloc, delegateOrFp, args);
125 }
126 
127 ///Note:from GC
128 @trusted auto newTask(alias fun, Args...)(Args args) {
129     return new Task!(fun, Args)(args);
130 }
131 
132 ///Note:from GC
133 @trusted auto newTask(F, Args...)(F delegateOrFp, Args args) if (is(typeof(delegateOrFp(args)))) {
134     return new Task!(run, F, Args)(delegateOrFp, args);
135 }
136 
137 struct TaskQueue {
138     AbstractTask front() nothrow {
139         return _frist;
140     }
141 
142     bool empty() nothrow {
143         return _frist is null;
144     }
145 
146     void enQueue(AbstractTask task) nothrow
147     in {
148         assert(task);
149     }
150     body {
151         if (_last) {
152             _last.next = task;
153         } else {
154             _frist = task;
155         }
156         task.next = null;
157         _last = task;
158     }
159 
160     AbstractTask deQueue() nothrow
161     in {
162         assert(_frist && _last);
163     }
164     body {
165         AbstractTask task = _frist;
166         _frist = _frist.next;
167         if (_frist is null)
168             _last = null;
169         return task;
170     }
171 
172 private:
173     AbstractTask _last = null;
174     AbstractTask _frist = null;
175 }
176 
177 unittest {
178     import std.functional;
179     int tfun() {
180         return 10;
181     }
182 
183     void finish(AbstractTask task) nothrow @trusted
184     {
185         import kiss.exception;
186         catchAndLogException((){
187                     import std.stdio;
188                     int a = task.returnValue.get!int();
189                     assert(task.status == TaskStatus.Finsh);
190                     assert(a == 10);
191                     writeln("-------------task call finish!!");
192                 }());
193     }
194 
195     AbstractTask test = newTask(&tfun);
196     test.finishedCall = toDelegate(&finish);
197     assert(test.status == TaskStatus.LDLE);
198     test.job();
199     int a = test.returnValue.get!int();
200     assert(test.status == TaskStatus.Finsh);
201     assert(a == 10);
202 
203 }