Implement test suite & prototypes for task global

This commit is contained in:
Filip Tibell 2023-01-21 15:07:18 -05:00
parent 8e8fb6c54f
commit d5b3d3f94b
No known key found for this signature in database
9 changed files with 158 additions and 11 deletions

1
Cargo.lock generated
View file

@ -516,6 +516,7 @@ dependencies = [
"anyhow",
"clap",
"mlua",
"once_cell",
"os_str_bytes",
"reqwest",
"serde",

View file

@ -26,7 +26,8 @@ panic = "abort" # Remove extra panic info
anyhow = { version = "1.0.68" }
clap = { version = "4.1.1", features = ["derive"] }
mlua = { version = "0.8.7", features = ["luau", "async", "serialize"] }
os_str_bytes = "6.4.1"
once_cell = { version = "1.17.0" }
os_str_bytes = { version = "6.4.1" }
reqwest = { version = "0.11.13", features = ["gzip", "deflate"] }
serde = { version = "1.0.152", features = ["derive"] }
serde_json = { version = "1.0.91" }

View file

@ -74,6 +74,20 @@ globals:
- required: false
type: table
# Task
task.defer:
args:
- type: thread | function
- type: "..."
task.delay:
args:
- required: false
type: number
- type: thread | function
- type: "..."
task.spawn:
args:
- type: thread | function
- type: "..."
task.wait:
args:
- required: false

View file

@ -53,5 +53,8 @@ declare process: {
}
declare task: {
defer: <A..., R...>(f: thread | (A...) -> (R...), A...) -> (R...),
delay: <A..., R...>(duration: number?, f: thread | (A...) -> (R...), A...) -> (R...),
spawn: <A..., R...>(f: thread | (A...) -> (R...), A...) -> (R...),
wait: (duration: number?) -> (number),
}

View file

@ -21,20 +21,36 @@ impl Default for Task {
impl UserData for Task {
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_async_function(
"defer",
|lua, (func, args): (Function, Variadic<Value>)| async move {
let thread = lua.create_thread(func)?;
thread.into_async(args).await?;
Ok(())
},
);
methods.add_async_function(
"delay",
|lua, (func, duration, args): (Function, Option<f32>, Variadic<Value>)| async move {
let secs = duration.unwrap_or(DEFAULT_SLEEP_DURATION);
time::sleep(Duration::from_secs_f32(secs)).await;
let thread = lua.create_thread(func)?;
thread.into_async(args).await?;
Ok(())
},
);
methods.add_async_function(
"spawn",
|lua, (func, args): (Function, Variadic<Value>)| async move {
let thread = lua.create_thread(func)?;
thread.into_async(args).await?;
Ok(())
},
);
methods.add_async_function("wait", |_, duration: Option<f32>| async move {
let secs = duration.unwrap_or(DEFAULT_SLEEP_DURATION);
time::sleep(Duration::from_secs_f32(secs)).await;
Ok(secs)
});
methods.add_async_function(
"spawn",
|lua, (func, args): (Function, Variadic<Value>)| async move {
let _thread = lua
.create_thread(func)?
.into_async::<_, Variadic<Value<'lua>>>(args);
// task::spawn_local(async move { thread });
Ok(())
},
);
}
}

View file

@ -109,6 +109,9 @@ mod tests {
net_request_redirect: "net/request/redirect",
net_json_decode: "net/json/decode",
net_json_encode: "net/json/encode",
task_defer: "task/defer",
task_delay: "task/delay",
task_spawn: "task/spawn",
task_wait: "task/wait",
}
}

45
src/tests/task/defer.luau Normal file
View file

@ -0,0 +1,45 @@
-- Deferred functions should run after other threads
local flag: boolean = false
task.defer(function()
flag = true
end)
assert(not flag, "Defer should run after other threads, including the main thread")
-- Deferred functions should work with yielding
local flag2: boolean = false
task.defer(function()
task.wait()
flag2 = true
end)
assert(not flag2, "Defer should work with yielding")
-- Deferred functions should run after other spawned threads
local flag3: boolean = false
task.defer(function()
if flag3 == true then
flag3 = false
end
end)
task.spawn(function()
if flag3 == false then
flag3 = true
end
end)
task.wait()
assert(not flag2, "Defer should run after spawned threads")
-- Varargs should get passed correctly
local function f(arg1: string, arg2: number, f2: (...any) -> ...any)
assert(type(arg1) == "string", "Invalid arg 1 passed to function")
assert(type(arg2) == "number", "Invalid arg 2 passed to function")
assert(type(arg3) == "function", "Invalid arg 3 passed to function")
end
task.defer(f, "", 1, f)
task.defer(f, "inf", math.huge, f)
task.defer(f, "NaN", 0 / 0, f)
task.wait(0.1)

34
src/tests/task/delay.luau Normal file
View file

@ -0,0 +1,34 @@
-- Delayed functions should never run right away
local flag: boolean = false
task.delay(0, function()
flag = true
end)
assert(not flag, "Delay should never run instantly")
-- Delayed functions should work with yielding
local flag2: boolean = false
task.delay(0.2, function()
flag2 = true
task.wait(0.2)
flag2 = false
end)
task.wait(0.25)
assert(flag2, "Delay should work with yielding")
task.wait(0.25)
assert(not flag2, "Delay should work with yielding")
-- Varargs should get passed correctly
local function f(arg1: string, arg2: number, f2: (...any) -> ...any)
assert(type(arg1) == "string", "Invalid arg 1 passed to function")
assert(type(arg2) == "number", "Invalid arg 2 passed to function")
assert(type(arg3) == "function", "Invalid arg 3 passed to function")
end
task.delay(0, f, "", 1, f)
task.delay(0, f, "inf", math.huge, f)
task.delay(0, f, "NaN", 0 / 0, f)
task.wait(0.1)

30
src/tests/task/spawn.luau Normal file
View file

@ -0,0 +1,30 @@
-- Spawned functions should run right away
local flag: boolean = false
task.spawn(function()
flag = true
end)
assert(flag, "Spawn should run instantly until yielded")
-- Spawned functions should work with yielding
local flag2: boolean = false
task.spawn(function()
task.wait()
flag2 = true
end)
assert(not flag2, "Spawn should work with yielding")
-- Varargs should get passed correctly
local function f(arg1: string, arg2: number, f2: (...any) -> ...any)
assert(type(arg1) == "string", "Invalid arg 1 passed to function")
assert(type(arg2) == "number", "Invalid arg 2 passed to function")
assert(type(arg3) == "function", "Invalid arg 3 passed to function")
end
task.spawn(f, "", 1, f)
task.spawn(f, "inf", math.huge, f)
task.spawn(f, "NaN", 0 / 0, f)
task.wait(0.1)