Skip to content

Commit 331a6c6

Browse files
ffrostfallaatxe
andauthored
Implement task.delay (#372)
This PR implements task.delay in the form of `<T..., U...>(dur: number | time.Duration, routine: (T...) -> U..., ...: T...)`. `yieldLuaStateFor` was also changed to accept an `nargs` parameter, to support using that function for `task.delay`. Closes #260 --------- Co-authored-by: ariel <[email protected]>
1 parent 774eba7 commit 331a6c6

File tree

4 files changed

+88
-8
lines changed

4 files changed

+88
-8
lines changed

definitions/task.luau

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,19 @@ function task.defer()
66
error("unimplemented")
77
end
88

9-
function task.wait(dur: (number | time.Duration)?)
9+
function task.wait(dur: (number | time.Duration)?): number
1010
error("unimplemented")
1111
end
1212

13-
function task.spawn<T..., U...>(routine: ((T...) -> U...) | thread, ...: T...)
13+
function task.spawn<T..., U...>(routine: ((T...) -> U...) | thread, ...: T...): thread
1414
error("unimplemented")
1515
end
1616

17-
function task.resume(thread: thread)
17+
function task.resume(thread: thread): thread
18+
error("unimplemented")
19+
end
20+
21+
function task.delay<T..., U...>(dur: number | time.Duration, routine: (T...) -> U..., ...: T...): thread
1822
error("unimplemented")
1923
end
2024

examples/task-delay.luau

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
local task = require("@lute/task")
2+
3+
task.delay(1, coroutine.create(print), vector.one)
4+
5+
task.delay(1, print, vector.one)

lute/task/include/lute/task.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@ int lua_defer(lua_State* L);
1515
int lua_wait(lua_State* L);
1616
int lua_spawn(lua_State* L);
1717
int lute_resume(lua_State* L);
18+
int lua_delay(lua_State* L);
1819

1920
static const luaL_Reg lib[] = {
2021
{"defer", lua_defer},
2122
{"wait", lua_wait},
2223
{"spawn", lua_spawn},
24+
{"delay", lua_delay},
2325

2426
{"resume", lute_resume},
2527

lute/task/src/task.cpp

Lines changed: 74 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <functional>
1212
#include <iterator>
1313

14+
1415
// taken from extern/luau/VM/lcorolib.cpp
1516
static const char* const statnames[] = {"running", "suspended", "normal", "dead", "dead"};
1617

@@ -23,10 +24,10 @@ struct WaitData
2324
uint64_t startedAtMs;
2425

2526
bool putDeltaTimeOnStack;
27+
int nargs;
2628
};
2729

28-
29-
static void yieldLuaStateFor(lua_State* L, uint64_t milliseconds, bool putDeltaTimeOnStack)
30+
static void yieldLuaStateFor(lua_State* L, uint64_t milliseconds, bool putDeltaTimeOnStack, int nargs)
3031
{
3132
WaitData* yield = new WaitData();
3233
uv_timer_init(uv_default_loop(), &yield->uvTimer);
@@ -35,6 +36,7 @@ static void yieldLuaStateFor(lua_State* L, uint64_t milliseconds, bool putDeltaT
3536
yield->startedAtMs = uv_now(uv_default_loop());
3637
yield->uvTimer.data = yield;
3738
yield->putDeltaTimeOnStack = putDeltaTimeOnStack;
39+
yield->nargs = nargs;
3840

3941
uv_timer_start(
4042
&yield->uvTimer,
@@ -45,8 +47,9 @@ static void yieldLuaStateFor(lua_State* L, uint64_t milliseconds, bool putDeltaT
4547
yield->resumptionToken->complete(
4648
[yield](lua_State* L)
4749
{
48-
int stackReturnAmount = yield->putDeltaTimeOnStack ? 1 : 0;
49-
if (stackReturnAmount)
50+
int stackReturnAmount = yield->putDeltaTimeOnStack ? yield->nargs + 1 : yield->nargs;
51+
52+
if (yield->putDeltaTimeOnStack)
5053
lua_pushnumber(L, static_cast<double>(uv_now(uv_default_loop()) - yield->startedAtMs) / 1000.0);
5154

5255
delete yield;
@@ -71,16 +74,80 @@ int lua_defer(lua_State* L)
7174
return lua_yield(L, 0);
7275
};
7376

77+
78+
int lua_delay(lua_State* L)
79+
{
80+
int type = lua_type(L, 1);
81+
uint64_t milliseconds = 0;
82+
83+
// Handle overloads
84+
switch (type)
85+
{
86+
case LUA_TNUMBER:
87+
milliseconds = static_cast<uint64_t>(lua_tonumber(L, 1) * 1000);
88+
break;
89+
90+
case LUA_TUSERDATA:
91+
{
92+
double seconds = getSecondsFromTimespec(getTimespecFromDuration(L, 1));
93+
milliseconds = static_cast<uint64_t>(seconds * 1000);
94+
break;
95+
}
96+
97+
default:
98+
luaL_errorL(L, "invalid type %s passed into task.delay", lua_typename(L, lua_type(L, 1)));
99+
break;
100+
};
101+
102+
// remove the wait time
103+
lua_remove(L, 1);
104+
105+
lua_State* passedLuaState;
106+
107+
if (lua_isfunction(L, 1))
108+
{
109+
lua_State* NL = lua_newthread(L);
110+
lua_pop(L, 1);
111+
112+
passedLuaState = NL;
113+
114+
// get the function
115+
lua_xpush(L, NL, 1);
116+
117+
// remove the function
118+
lua_remove(L, 1);
119+
}
120+
else if (lua_isthread(L, 1))
121+
{
122+
passedLuaState = lua_tothread(L, 1);
123+
lua_remove(L, 1);
124+
}
125+
else
126+
{
127+
luaL_error(L, "can only pass threads or functions to task.spawn");
128+
};
129+
130+
int nargs = lua_gettop(L);
131+
lua_xmove(L, passedLuaState, nargs);
132+
133+
yieldLuaStateFor(passedLuaState, milliseconds, false, nargs);
134+
135+
return 1;
136+
}
137+
74138
int lua_spawn(lua_State* L)
75139
{
76140
if (lua_isfunction(L, 1))
77141
{
78142
lua_State* NL = lua_newthread(L);
79143

144+
// transfer arguments from other lua_State to the called lua_State
80145
lua_xpush(L, NL, 1);
81146

147+
// remove the function arg
82148
lua_remove(L, 1);
83149

150+
// insert the thread
84151
lua_insert(L, 1);
85152
}
86153
else if (!lua_isthread(L, 1))
@@ -89,6 +156,8 @@ int lua_spawn(lua_State* L)
89156
}
90157

91158
lute_resume(L);
159+
160+
// return the thread
92161
return 1;
93162
}
94163

@@ -116,7 +185,7 @@ int lua_wait(lua_State* L)
116185
break;
117186
};
118187

119-
yieldLuaStateFor(L, milliseconds, true);
188+
yieldLuaStateFor(L, milliseconds, true, 0);
120189

121190
return lua_yield(L, 0);
122191
}

0 commit comments

Comments
 (0)