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