ETTask.lua.txt 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. --[[
  2. Copyright 2017 YANG Huan (sy.yanghuan@gmail.com).
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. --]]
  13. local System = System
  14. local define = System.define
  15. local defStc = System.defStc
  16. local throw = System.throw
  17. local try = System.try
  18. local trunc = System.trunc
  19. local Void = System.Void
  20. local post = System.post
  21. local addTimer = System.addTimer
  22. local removeTimer = System.removeTimer
  23. local waitTask = System.Thread.waitTask
  24. local arrayFromTable = System.arrayFromTable
  25. local Exception = System.Exception
  26. local NullReferenceException = System.NullReferenceException
  27. local NotSupportedException = System.NotSupportedException
  28. local NotImplementedException = System.NotImplementedException
  29. local ArgumentException = System.ArgumentException
  30. local ArgumentNullException = System.ArgumentNullException
  31. local ArgumentOutOfRangeException = System.ArgumentOutOfRangeException
  32. local InvalidOperationException = System.InvalidOperationException
  33. local AggregateException = System.AggregateException
  34. local ObjectDisposedException = System.ObjectDisposedException
  35. local ccreate = System.ccreate
  36. local cpool = System.cpool
  37. local cresume = System.cresume
  38. local cyield = System.yield
  39. local type = type
  40. local table = table
  41. local select = select
  42. local assert = assert
  43. local getmetatable = getmetatable
  44. local setmetatable = setmetatable
  45. local tremove = table.remove
  46. local pack = table.pack
  47. local unpack = table.unpack
  48. local error = error
  49. local AwaiterStatusPending = 0
  50. local AwaiterStatusSucceeded = 1
  51. local AwaiterStatusFaulted = 2
  52. local function newTaskExceptionHolder(task, exception)
  53. return setmetatable({ task = task, exception = exception }, TaskExceptionHolder)
  54. end
  55. local function getException(task, await)
  56. local holder = task.data
  57. if not holder.isHandled then
  58. holder.isHandled = true
  59. end
  60. local e = holder.exception
  61. if await then
  62. return e
  63. end
  64. return AggregateException(e)
  65. end
  66. local ETTask
  67. local function isCompleted(this)
  68. local status = this.status
  69. return status ~= AwaiterStatusPending
  70. end
  71. local function createETTask(...)
  72. local fromPool
  73. if(select('#', ...) == 1)then
  74. fromPool = ...
  75. end
  76. if not fromPool then
  77. local this = setmetatable({}, ETTask)
  78. return this, ETTask.__ctor__(this)
  79. end
  80. local this = setmetatable({}, ETTask)
  81. return this, ETTask.__ctor__(this)
  82. end
  83. local function newTask(status, data)
  84. local task= createETTask();
  85. task.data=data
  86. status = status or AwaiterStatusPending
  87. task.status = status
  88. return task
  89. end
  90. local function fromException(exception)
  91. local data = newTaskExceptionHolder(false, exception)
  92. local t = newTask(AwaiterStatusFaulted, data)
  93. data.task = t
  94. return t
  95. end
  96. local function trySetComplete(this, status, data)
  97. if isCompleted(this) then
  98. return false
  99. end
  100. this.status = status
  101. this.data = data
  102. local continueActions = this.continueActions
  103. if continueActions then
  104. for i = 1, #continueActions do
  105. continueActions[i](this)
  106. end
  107. this.continueActions = nil
  108. end
  109. return true
  110. end
  111. local function trySetResult(this, result)
  112. return trySetComplete(this, AwaiterStatusSucceeded, result)
  113. end
  114. local function trySetException(this, exception)
  115. if this.data == Void then
  116. throw(exception)
  117. end
  118. return trySetComplete(this, AwaiterStatusFaulted, newTaskExceptionHolder(this, exception))
  119. end
  120. local function newWaitingTask(isVoid)
  121. return newTask(AwaiterStatusPending, isVoid and Void)
  122. end
  123. local function getContinueActions(task)
  124. local continueActions = task.continueActions
  125. if continueActions == nil then
  126. continueActions = {}
  127. task.continueActions = continueActions
  128. end
  129. return continueActions
  130. end
  131. local function addContinueAction(task, f)
  132. local continueActions = getContinueActions(task)
  133. continueActions[#continueActions + 1] = assert(f)
  134. end
  135. local waitToken = {}
  136. local function getResult(this, await)
  137. local status = this.status
  138. if status == AwaiterStatusSucceeded then
  139. return this.data
  140. elseif status == AwaiterStatusFaulted then
  141. throw(getException(this, await))
  142. else
  143. throw(NotSupportedException("ETTask does not allow call GetResult directly when task not completed. Please use 'await'."))
  144. end
  145. return waitToken
  146. end
  147. local function getAwaitResult(task)
  148. local status = task.status
  149. local ok, v
  150. if status == AwaiterStatusSucceeded then
  151. ok, v = true, task.data
  152. elseif status == AwaiterStatusFaulted then
  153. ok, v = false, getException(task, true)
  154. else
  155. throw(NotSupportedException("ETTask does not allow call GetResult directly when task not completed. Please use 'await'."))
  156. end
  157. return ok, v
  158. end
  159. local ETTaskAwaiter
  160. ETTaskAwaiter = define("ET.ETTaskAwaiter", {
  161. __ctor__ = function(this, t)
  162. this.task = t
  163. end,
  164. getIsCompleted = function(this)
  165. return this.task.status ~= AwaiterStatusPending
  166. end,
  167. GetResult = function(this)
  168. local status = this.task.status
  169. if status == AwaiterStatusSucceeded then
  170. return this.task.data
  171. elseif status == AwaiterStatusFaulted then
  172. throw(getException(this.task, this))
  173. else
  174. throw(NotSupportedException("ETTask does not allow call GetResult directly when task not completed. Please use 'await'."))
  175. end
  176. end,
  177. OnCompleted = function(this, f)
  178. if this.task.status ~= AwaiterStatusPending then
  179. if f then
  180. f()
  181. return
  182. end
  183. end
  184. addContinueAction(this.task, f)
  185. end
  186. })
  187. ETTask = define("ET.ETTask", {
  188. Dispose = System.emptyFn,
  189. __ctor__ = function(this)
  190. this.fromPool = false
  191. this.data = nil
  192. this.awaiter = ETTaskAwaiter(this)
  193. end,
  194. getResult = function(this)
  195. local result = getResult(this)
  196. if result == waitToken then
  197. waitTask(getContinueActions(this))
  198. result = getResult(this)
  199. assert(result ~= waitToken)
  200. end
  201. return result
  202. end,
  203. getIsCompleted = isCompleted,
  204. GetAwaiter = function(this)
  205. return this.awaiter
  206. end,
  207. Create = function(...)
  208. local task= createETTask(...);
  209. status = AwaiterStatusPending
  210. task.status = status
  211. return task
  212. end,
  213. getCompletedTask = function()
  214. return newTask(AwaiterStatusSucceeded, nil)
  215. end,
  216. Await = function(this, t)
  217. local a = t:GetAwaiter()
  218. if a:getIsCompleted() then
  219. return a:GetResult()
  220. end
  221. a:OnCompleted(function()
  222. local ok, v
  223. try(function()
  224. ok, v = true, a:GetResult()
  225. end, function(e)
  226. ok, v = false, e
  227. end)
  228. ok, v = cresume(this.c, ok, v)
  229. if not ok then
  230. assert(trySetException(this, v))
  231. end
  232. end)
  233. local ok, v = cyield()
  234. if ok then
  235. return v
  236. else
  237. error(v)
  238. end
  239. end,
  240. SetResult = function(this, result)
  241. if not trySetResult(this, result) then
  242. throw(InvalidOperationException(TaskT_TransitionToFinal_AlreadyCompleted))
  243. end
  244. end,
  245. SetException = function(this, exception)
  246. if not trySetException(this, exception) then
  247. throw(InvalidOperationException(TaskT_TransitionToFinal_AlreadyCompleted))
  248. end
  249. end,
  250. Coroutine=function(this)
  251. end,
  252. TrySetResult = trySetResult,
  253. await = function(this, task)
  254. if getmetatable(task) ~= ETTask then
  255. return this:Await(task)
  256. end
  257. local result = getResult(task, true)
  258. if result ~= waitToken then
  259. return result
  260. end
  261. addContinueAction(task, function(task)
  262. local ok, v = getAwaitResult(task)
  263. ok, v = cresume(this.c, ok, v)
  264. if not ok then
  265. assert(trySetException(this, v))
  266. end
  267. end)
  268. local ok, v = cyield()
  269. if ok then
  270. return v
  271. else
  272. error(v)
  273. end
  274. end
  275. })
  276. ET.ETTask = ETTask
  277. local ETTask_1 = define("ET.ETTask_1", function(T)
  278. return ETTask
  279. end)
  280. ET.ETTask_1 = ETTask_1
  281. local function taskCoroutineCreate(t, f)
  282. local fun = function(...)
  283. local r = f(t, ...)
  284. assert(trySetResult(t, r))
  285. end
  286. local c = ccreate(fun)
  287. t.c = c
  288. return c
  289. end
  290. function System.async(f, void, ...)
  291. local task = newWaitingTask(void)
  292. local c = taskCoroutineCreate(task, f)
  293. local ok, v = cresume(c, ...)
  294. if not ok then
  295. assert(trySetException(task, v))
  296. end
  297. return task
  298. end