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 }