Add support for user tasks, deprecate native task:await()

This commit is contained in:
Alessandro Proto 2023-03-15 21:29:33 +01:00
parent b2e7969793
commit a84aedbe38
2 changed files with 112 additions and 3 deletions

View file

@ -14,6 +14,7 @@
// limitations under the License. // limitations under the License.
using Capy64.API; using Capy64.API;
using Capy64.Runtime.Objects;
using KeraLua; using KeraLua;
using System; using System;
@ -26,6 +27,8 @@ public class Event : IComponent
private static Lua UserQueue; private static Lua UserQueue;
private static bool FrozenTaskAwaiter = false;
private static IGame _game; private static IGame _game;
public Event(IGame game) public Event(IGame game)
{ {
@ -49,15 +52,36 @@ public class Event : IComponent
name = "push", name = "push",
function = L_Push, function = L_Push,
}, },
new()
{
name = "setAwaiter",
function = L_SetTaskAwaiter,
},
new()
{
name = "fulfill",
function = L_Fulfill,
},
new()
{
name = "reject",
function = L_Reject,
},
new()
{
name = "newTask",
function = L_NewTask,
},
new(), new(),
}; };
public void LuaInit(Lua L) public void LuaInit(Lua L)
{ {
PushQueue = 0; PushQueue = 0;
UserQueue = _game.LuaRuntime.Parent.NewThread(); UserQueue = _game.LuaRuntime.Parent.NewThread();
FrozenTaskAwaiter = false;
L.RequireF("event", OpenLib, false); L.RequireF("event", OpenLib, false);
} }
@ -140,4 +164,86 @@ public class Event : IComponent
return 0; return 0;
} }
private static int L_SetTaskAwaiter(IntPtr state)
{
var L = Lua.FromIntPtr(state);
L.CheckType(1, LuaType.Function);
if (FrozenTaskAwaiter)
{
L.Error("awaiter is frozen");
}
FrozenTaskAwaiter = L.ToBoolean(2);
L.GetMetaTable(TaskMeta.ObjectType);
L.GetField(-1, "__index");
L.Rotate(1, -1);
L.SetField(-2, "await");
L.Pop(2);
return 0;
}
private static int L_Fulfill(IntPtr state)
{
var L = Lua.FromIntPtr(state);
var task = TaskMeta.CheckTask(L, false);
L.CheckAny(2);
if(!task.UserTask)
{
L.Error("attempt to fulfill machine task");
}
if (task.Status != TaskMeta.TaskStatus.Running)
{
L.Error("attempt to fulfill a finished task");
}
task.Fulfill(lk =>
{
L.XMove(lk, 1);
});
return 0;
}
private static int L_Reject(IntPtr state)
{
var L = Lua.FromIntPtr(state);
var task = TaskMeta.CheckTask(L, false);
var error = L.CheckString(2);
if (!task.UserTask)
{
L.Error("attempt to reject machine task");
}
if(task.Status != TaskMeta.TaskStatus.Running)
{
L.Error("attempt to reject a finished task");
}
task.Reject(error);
return 0;
}
private static int L_NewTask(IntPtr state)
{
var L = Lua.FromIntPtr(state);
var name = L.OptString(1, "object");
var task = TaskMeta.Push(L, name);
task.UserTask = true;
return 1;
}
} }

View file

@ -56,6 +56,7 @@ public class TaskMeta : IComponent
public TaskStatus Status { get; set; } = TaskStatus.Running; public TaskStatus Status { get; set; } = TaskStatus.Running;
public string Error { get; private set; } public string Error { get; private set; }
public int DataIndex { get; private set; } = 0; public int DataIndex { get; private set; } = 0;
public bool UserTask { get; set; } = false;
public void Fulfill(Action<Lua> lk) public void Fulfill(Action<Lua> lk)
{ {
@ -191,12 +192,12 @@ public class TaskMeta : IComponent
return task; return task;
} }
private static RuntimeTask ToTask(Lua L, bool gc = false) public static RuntimeTask ToTask(Lua L, bool gc = false)
{ {
return ObjectManager.ToObject<RuntimeTask>(L, 1, gc); return ObjectManager.ToObject<RuntimeTask>(L, 1, gc);
} }
private static RuntimeTask CheckTask(Lua L, bool gc = false) public static RuntimeTask CheckTask(Lua L, bool gc = false)
{ {
var obj = ObjectManager.CheckObject<RuntimeTask>(L, 1, ObjectType, gc); var obj = ObjectManager.CheckObject<RuntimeTask>(L, 1, ObjectType, gc);
if (obj is null) if (obj is null)
@ -218,6 +219,8 @@ public class TaskMeta : IComponent
{ {
var L = Lua.FromIntPtr(state); var L = Lua.FromIntPtr(state);
L.Warning("Native task awaiter should be avoided", false);
var task = CheckTask(L, false); var task = CheckTask(L, false);
if (task.Status == TaskStatus.Succeeded) if (task.Status == TaskStatus.Succeeded)