98 lines
2.5 KiB
Plaintext
98 lines
2.5 KiB
Plaintext
--!strict
|
|
--[[
|
|
Abstraction layer between Fusion internals and external environments,
|
|
allowing for flexible integration with schedulers and test mocks.
|
|
]]
|
|
|
|
local logError = require "./Logging/logError"
|
|
|
|
local External = {}
|
|
|
|
export type Scheduler = {
|
|
doTaskImmediate: (resume: () -> ()) -> (),
|
|
doTaskDeferred: (resume: () -> ()) -> (),
|
|
startScheduler: () -> (),
|
|
stopScheduler: () -> (),
|
|
}
|
|
|
|
local updateStepCallbacks = {}
|
|
local currentScheduler: Scheduler? = nil
|
|
local lastUpdateStep = 0
|
|
|
|
--[[
|
|
Sets the external scheduler that Fusion will use for queuing async tasks.
|
|
Returns the previous scheduler so it can be reset later.
|
|
]]
|
|
function External.setExternalScheduler(newScheduler: Scheduler?): Scheduler?
|
|
local oldScheduler = currentScheduler
|
|
if oldScheduler ~= nil then
|
|
oldScheduler.stopScheduler()
|
|
end
|
|
currentScheduler = newScheduler
|
|
if newScheduler ~= nil then
|
|
newScheduler.startScheduler()
|
|
end
|
|
return oldScheduler
|
|
end
|
|
|
|
--[[
|
|
Sends an immediate task to the external scheduler. Throws if none is set.
|
|
]]
|
|
function External.doTaskImmediate(resume: () -> ())
|
|
if currentScheduler == nil then
|
|
logError "noTaskScheduler"
|
|
else
|
|
currentScheduler.doTaskImmediate(resume)
|
|
end
|
|
end
|
|
|
|
--[[
|
|
Sends a deferred task to the external scheduler. Throws if none is set.
|
|
]]
|
|
function External.doTaskDeferred(resume: () -> ())
|
|
if currentScheduler == nil then
|
|
logError "noTaskScheduler"
|
|
else
|
|
currentScheduler.doTaskDeferred(resume)
|
|
end
|
|
end
|
|
|
|
--[[
|
|
Registers a callback to the update step of the external scheduler.
|
|
Returns a function that can be used to disconnect later.
|
|
|
|
Callbacks are given the current number of seconds since an arbitrary epoch.
|
|
|
|
TODO: This epoch may change between schedulers. We could investigate ways
|
|
of allowing schedulers to co-operate to keep the epoch the same, so that
|
|
monotonicity can be better preserved.
|
|
]]
|
|
function External.bindToUpdateStep(callback: (now: number) -> ()): () -> ()
|
|
local uniqueIdentifier = {}
|
|
updateStepCallbacks[uniqueIdentifier] = callback
|
|
return function()
|
|
updateStepCallbacks[uniqueIdentifier] = nil
|
|
end
|
|
end
|
|
|
|
--[[
|
|
Steps time-dependent systems with the current number of seconds since an
|
|
arbitrary epoch. This should be called as early as possible in the external
|
|
scheduler's update cycle.
|
|
]]
|
|
function External.performUpdateStep(now: number)
|
|
lastUpdateStep = now
|
|
for _, callback in pairs(updateStepCallbacks) do
|
|
callback(now)
|
|
end
|
|
end
|
|
|
|
--[[
|
|
Returns the timestamp of the last update step.
|
|
]]
|
|
function External.lastUpdateStep()
|
|
return lastUpdateStep
|
|
end
|
|
|
|
return External
|