| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327 |
- --[[
- Copyright 2017 YANG Huan (sy.yanghuan@gmail.com).
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- --]]
- local System = System
- local define = System.define
- local defStc = System.defStc
- local throw = System.throw
- local try = System.try
- local trunc = System.trunc
- local Void = System.Void
- local post = System.post
- local addTimer = System.addTimer
- local removeTimer = System.removeTimer
- local waitTask = System.Thread.waitTask
- local arrayFromTable = System.arrayFromTable
- local Exception = System.Exception
- local NullReferenceException = System.NullReferenceException
- local NotSupportedException = System.NotSupportedException
- local NotImplementedException = System.NotImplementedException
- local ArgumentException = System.ArgumentException
- local ArgumentNullException = System.ArgumentNullException
- local ArgumentOutOfRangeException = System.ArgumentOutOfRangeException
- local InvalidOperationException = System.InvalidOperationException
- local AggregateException = System.AggregateException
- local ObjectDisposedException = System.ObjectDisposedException
- local ccreate = System.ccreate
- local cpool = System.cpool
- local cresume = System.cresume
- local cyield = System.yield
- local type = type
- local table = table
- local select = select
- local assert = assert
- local getmetatable = getmetatable
- local setmetatable = setmetatable
- local tremove = table.remove
- local pack = table.pack
- local unpack = table.unpack
- local error = error
- local AwaiterStatusPending = 0
- local AwaiterStatusSucceeded = 1
- local AwaiterStatusFaulted = 2
- local function newTaskExceptionHolder(task, exception)
- return setmetatable({ task = task, exception = exception }, TaskExceptionHolder)
- end
- local function getException(task, await)
- local holder = task.data
- if not holder.isHandled then
- holder.isHandled = true
- end
- local e = holder.exception
- if await then
- return e
- end
- return AggregateException(e)
- end
- local ETTask
- local function isCompleted(this)
- local status = this.status
- return status ~= AwaiterStatusPending
- end
- local function createETTask(...)
- local fromPool
- if(select('#', ...) == 1)then
- fromPool = ...
- end
- if not fromPool then
- local this = setmetatable({}, ETTask)
- return this, ETTask.__ctor__(this)
- end
- local this = setmetatable({}, ETTask)
- return this, ETTask.__ctor__(this)
- end
- local function newTask(status, data)
- local task= createETTask();
- task.data=data
- status = status or AwaiterStatusPending
- task.status = status
- return task
- end
- local function fromException(exception)
- local data = newTaskExceptionHolder(false, exception)
- local t = newTask(AwaiterStatusFaulted, data)
- data.task = t
- return t
- end
- local function trySetComplete(this, status, data)
- if isCompleted(this) then
- return false
- end
- this.status = status
- this.data = data
- local continueActions = this.continueActions
- if continueActions then
- for i = 1, #continueActions do
- continueActions[i](this)
- end
- this.continueActions = nil
- end
- return true
- end
- local function trySetResult(this, result)
- return trySetComplete(this, AwaiterStatusSucceeded, result)
- end
- local function trySetException(this, exception)
- if this.data == Void then
- throw(exception)
- end
- return trySetComplete(this, AwaiterStatusFaulted, newTaskExceptionHolder(this, exception))
- end
- local function newWaitingTask(isVoid)
- return newTask(AwaiterStatusPending, isVoid and Void)
- end
- local function getContinueActions(task)
- local continueActions = task.continueActions
- if continueActions == nil then
- continueActions = {}
- task.continueActions = continueActions
- end
- return continueActions
- end
- local function addContinueAction(task, f)
- local continueActions = getContinueActions(task)
- continueActions[#continueActions + 1] = assert(f)
- end
- local waitToken = {}
- local function getResult(this, await)
- local status = this.status
- if status == AwaiterStatusSucceeded then
- return this.data
- elseif status == AwaiterStatusFaulted then
- throw(getException(this, await))
- else
- throw(NotSupportedException("ETTask does not allow call GetResult directly when task not completed. Please use 'await'."))
- end
- return waitToken
- end
- local function getAwaitResult(task)
- local status = task.status
- local ok, v
- if status == AwaiterStatusSucceeded then
- ok, v = true, task.data
- elseif status == AwaiterStatusFaulted then
- ok, v = false, getException(task, true)
- else
- throw(NotSupportedException("ETTask does not allow call GetResult directly when task not completed. Please use 'await'."))
- end
- return ok, v
- end
- local ETTaskAwaiter
- ETTaskAwaiter = define("ET.ETTaskAwaiter", {
- __ctor__ = function(this, t)
- this.task = t
- end,
- getIsCompleted = function(this)
- return this.task.status ~= AwaiterStatusPending
- end,
- GetResult = function(this)
- local status = this.task.status
- if status == AwaiterStatusSucceeded then
- return this.task.data
- elseif status == AwaiterStatusFaulted then
- throw(getException(this.task, this))
- else
- throw(NotSupportedException("ETTask does not allow call GetResult directly when task not completed. Please use 'await'."))
- end
- end,
- OnCompleted = function(this, f)
- if this.task.status ~= AwaiterStatusPending then
- if f then
- f()
- return
- end
- end
- addContinueAction(this.task, f)
- end
- })
- ETTask = define("ET.ETTask", {
- Dispose = System.emptyFn,
- __ctor__ = function(this)
- this.fromPool = false
- this.data = nil
- this.awaiter = ETTaskAwaiter(this)
- end,
- getResult = function(this)
- local result = getResult(this)
- if result == waitToken then
- waitTask(getContinueActions(this))
- result = getResult(this)
- assert(result ~= waitToken)
- end
- return result
- end,
- getIsCompleted = isCompleted,
- GetAwaiter = function(this)
- return this.awaiter
- end,
- Create = function(...)
- local task= createETTask(...);
- status = AwaiterStatusPending
- task.status = status
- return task
- end,
- getCompletedTask = function()
- return newTask(AwaiterStatusSucceeded, nil)
- end,
- Await = function(this, t)
- local a = t:GetAwaiter()
- if a:getIsCompleted() then
- return a:GetResult()
- end
- a:OnCompleted(function()
- local ok, v
- try(function()
- ok, v = true, a:GetResult()
- end, function(e)
- ok, v = false, e
- end)
- ok, v = cresume(this.c, ok, v)
- if not ok then
- assert(trySetException(this, v))
- end
- end)
- local ok, v = cyield()
- if ok then
- return v
- else
- error(v)
- end
- end,
- SetResult = function(this, result)
- if not trySetResult(this, result) then
- throw(InvalidOperationException(TaskT_TransitionToFinal_AlreadyCompleted))
- end
- end,
- SetException = function(this, exception)
- if not trySetException(this, exception) then
- throw(InvalidOperationException(TaskT_TransitionToFinal_AlreadyCompleted))
- end
- end,
- Coroutine=function(this)
- end,
- TrySetResult = trySetResult,
- await = function(this, task)
- if getmetatable(task) ~= ETTask then
- return this:Await(task)
- end
- local result = getResult(task, true)
- if result ~= waitToken then
- return result
- end
- addContinueAction(task, function(task)
- local ok, v = getAwaitResult(task)
- ok, v = cresume(this.c, ok, v)
- if not ok then
- assert(trySetException(this, v))
- end
- end)
- local ok, v = cyield()
- if ok then
- return v
- else
- error(v)
- end
- end
- })
- ET.ETTask = ETTask
- local ETTask_1 = define("ET.ETTask_1", function(T)
- return ETTask
- end)
- ET.ETTask_1 = ETTask_1
- local function taskCoroutineCreate(t, f)
- local fun = function(...)
- local r = f(t, ...)
- assert(trySetResult(t, r))
- end
- local c = ccreate(fun)
- t.c = c
- return c
- end
- function System.async(f, void, ...)
- local task = newWaitingTask(void)
- local c = taskCoroutineCreate(task, f)
- local ok, v = cresume(c, ...)
- if not ok then
- assert(trySetException(task, v))
- end
- return task
- end
|