-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
load styles for 1.92 previews in a separate thread
- Loading branch information
Showing
7 changed files
with
255 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
-- small async implementation using coroutines to suspend a function awaiting a callback | ||
local promise = {} | ||
promise.__index = promise | ||
|
||
function promise:new(fn) | ||
local obj = setmetatable({ | ||
done_callbacks = {}, | ||
error_callbacks = {}, | ||
executed = false | ||
}, promise) | ||
fn(function(...) | ||
obj.executed = true | ||
for i = 1, #obj.done_callbacks do | ||
obj.done_callbacks[i](...) | ||
end | ||
end, function(...) | ||
obj.executed = true | ||
for i = 1, #obj.error_callbacks do | ||
obj.error_callbacks[i](...) | ||
end | ||
if #obj.error_callbacks == 0 then | ||
print("Error: ", ...) | ||
error("Uncaught error in promise") | ||
end | ||
end) | ||
return obj | ||
end | ||
|
||
function promise:done(callback) | ||
self.done_callbacks[#self.done_callbacks + 1] = callback | ||
return self | ||
end | ||
|
||
function promise:err(callback) | ||
self.error_callback[#self.error_callback + 1] = callback | ||
return self | ||
end | ||
|
||
local async = setmetatable({}, { | ||
__call = function(_, fn) | ||
return function(...) | ||
local args = {...} | ||
return promise:new(function(resolve, reject) | ||
local co = coroutine.create(function() | ||
local ret = {xpcall(fn, reject, unpack(args))} | ||
if ret[1] then | ||
resolve(unpack(ret, 2)) | ||
end | ||
end) | ||
coroutine.resume(co) | ||
end) | ||
end | ||
end | ||
}) | ||
|
||
async.await = function(prom) | ||
local co = coroutine.running() | ||
if not co then | ||
error("cannot await outide of an async function") | ||
end | ||
prom:done(function(...) | ||
coroutine.resume(co, ...) | ||
end) | ||
return coroutine.yield() | ||
end | ||
|
||
async.promise = promise | ||
|
||
return async |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
local log = require("log")("threadify") | ||
local modname, is_thread = ... | ||
|
||
if is_thread then | ||
local api = require(modname) | ||
local run = true | ||
while run do | ||
local cmd = love.thread.getChannel(modname .. "_cmd"):demand() | ||
local call_id = cmd[1] | ||
local out_channel = love.thread.getChannel(modname .. "_out") | ||
xpcall(function() | ||
local fn = api[cmd[2]] | ||
out_channel:push({ call_id, true, fn(unpack(cmd, 3)) }) | ||
end, function(err) | ||
out_channel:push({ call_id, false, "Failed to call '" .. modname .. "." .. cmd[2] .. "'", err }) | ||
end) | ||
end | ||
else | ||
local async = require("async") | ||
local threads = {} | ||
local thread_names = {} | ||
local threadify = {} | ||
|
||
function threadify.require(require_string) | ||
if not threads[require_string] then | ||
local thread_table = { | ||
thread = love.thread.newThread("threadify.lua"), | ||
resolvers = {}, | ||
rejecters = {}, | ||
free_indices = {}, | ||
} | ||
thread_table.thread:start(require_string, true) | ||
threads[require_string] = thread_table | ||
thread_names[#thread_names + 1] = require_string | ||
end | ||
local thread = threads[require_string] | ||
local interface = {} | ||
return setmetatable(interface, { | ||
__index = function(_, key) | ||
return function(...) | ||
local msg = {-1, key, ...} | ||
return async.promise:new(function(resolve, reject) | ||
local index = 0 | ||
if #thread.free_indices == 0 then | ||
index = #thread.resolvers + 1 | ||
else | ||
local last_index = #thread.free_indices | ||
index = thread.free_indices[last_index] | ||
thread.free_indices[last_index] = nil | ||
end | ||
msg[1] = index | ||
love.thread.getChannel(require_string .. "_cmd"):push(msg) | ||
thread.resolvers[index] = resolve | ||
thread.rejecters[index] = reject | ||
end) | ||
end | ||
end | ||
}) | ||
end | ||
|
||
function threadify.update() | ||
for i = 1, #thread_names do | ||
local require_string = thread_names[i] | ||
local thread = threads[require_string] | ||
local result = love.thread.getChannel(require_string .. "_out"):pop() | ||
if result then | ||
if result[2] then | ||
thread.resolvers[result[1]](unpack(result, 3)) | ||
else | ||
log(result[3]) | ||
thread.rejecters[result[1]](result[4]) | ||
end | ||
thread.resolvers[result[1]] = nil | ||
thread.rejecters[result[1]] = nil | ||
thread.free_indices[#thread.free_indices + 1] = result[1] | ||
end | ||
end | ||
end | ||
|
||
function threadify.stop() | ||
for require_string, thread_table in pairs(threads) do | ||
local thread = thread_table.thread | ||
if thread:isRunning() then | ||
-- effectively kills the thread (sending stop doesn't work sometimes and when it does it would still cause unresponsiveness on closing) | ||
thread:release() | ||
else | ||
local err = thread:getError() | ||
if err then | ||
log("Error in '" .. require_string .. "' thread: " .. err) | ||
end | ||
end | ||
end | ||
end | ||
|
||
return threadify | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters