mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-03-09 21:18:13 +00:00
Don't round trip values in executeMainThreadTask
I've been meaning to fix this for over 6 years, and just kept forgetting. Previously ILuaContext.executeMainThreadTask worked by running ILuaContext.issueMainThreadTask, pulling task_complete events, and then returning the results. While this makes the implementation simple, it means that the task's results were converted into Lua values (in order to queue the event) and then back into Java ones (when the event was pulled), before eventually being converted into Lua once more. Not only is this inefficient, as roundtripping isn't lossless, you couldn't return functions or rich objects from main thread functions (see https://github.com/dan200/ComputerCraft/issues/125). We now store the return value on the Java side and then return that when the receiving the task_complete event - the event no longer carries the result. Note this does not affect methods using issueMainThreadTask!
This commit is contained in:
parent
2b237332ce
commit
e7fe22d4f8
@ -5,37 +5,59 @@
|
|||||||
*/
|
*/
|
||||||
package dan200.computercraft.api.lua;
|
package dan200.computercraft.api.lua;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
|
|
||||||
final class TaskCallback implements ILuaCallback {
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
final class TaskCallback implements ILuaCallback, LuaTask {
|
||||||
|
private final LuaTask task;
|
||||||
|
|
||||||
|
private volatile @Nullable Object[] result;
|
||||||
|
private volatile @MonotonicNonNull LuaException failure;
|
||||||
|
|
||||||
|
private final long taskId;
|
||||||
private final MethodResult pull = MethodResult.pullEvent("task_complete", this);
|
private final MethodResult pull = MethodResult.pullEvent("task_complete", this);
|
||||||
private final long task;
|
|
||||||
|
|
||||||
private TaskCallback(long task) {
|
private TaskCallback(ILuaContext context, LuaTask task) throws LuaException {
|
||||||
this.task = task;
|
this.task = task;
|
||||||
|
taskId = context.issueMainThreadTask(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Object[] execute() throws LuaException {
|
||||||
|
// Store the result/exception: we read these back when receiving the task_complete event.
|
||||||
|
try {
|
||||||
|
result = task.execute();
|
||||||
|
return null;
|
||||||
|
} catch (LuaException e) {
|
||||||
|
// We only care about storing LuaExceptions as we want also want to preserve custom error levels: other
|
||||||
|
// exceptions won't have this extra data!
|
||||||
|
failure = e;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MethodResult resume(Object[] response) throws LuaException {
|
public MethodResult resume(Object[] response) throws LuaException {
|
||||||
if (response.length < 3 || !(response[1] instanceof Number) || !(response[2] instanceof Boolean)) {
|
if (response.length < 3 || !(response[1] instanceof Number eventTask) || !(response[2] instanceof Boolean isOk)) {
|
||||||
return pull;
|
return pull;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((Number) response[1]).longValue() != task) return pull;
|
if (eventTask.longValue() != taskId) return pull;
|
||||||
|
|
||||||
if ((Boolean) response[2]) {
|
if (isOk) {
|
||||||
// Extract the return values from the event and return them
|
return MethodResult.of(result);
|
||||||
return MethodResult.of(Arrays.copyOfRange(response, 3, response.length));
|
} else if (failure != null) {
|
||||||
} else if (response.length >= 4 && response[3] instanceof String) {
|
throw failure;
|
||||||
// Extract the error message from the event and raise it
|
} else if (response.length >= 4 && response[3] instanceof String message) {
|
||||||
throw new LuaException((String) response[3]);
|
throw new LuaException(message);
|
||||||
} else {
|
} else {
|
||||||
throw new LuaException("error");
|
throw new LuaException("error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static MethodResult make(ILuaContext context, LuaTask func) throws LuaException {
|
static MethodResult make(ILuaContext context, LuaTask func) throws LuaException {
|
||||||
var task = context.issueMainThreadTask(func);
|
return new TaskCallback(context, func).pull;
|
||||||
return new TaskCallback(task).pull;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,11 @@ public class MethodTest {
|
|||||||
50);
|
50);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMainThreadReturnObject() {
|
||||||
|
ComputerBootstrap.run("assert(type(main_thread.complex().go) == \"function\")", x -> x.addApi(new MainThread()), 50);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDynamic() {
|
public void testDynamic() {
|
||||||
ComputerBootstrap.run(
|
ComputerBootstrap.run(
|
||||||
@ -98,6 +103,11 @@ public class MethodTest {
|
|||||||
return 123;
|
return 123;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@LuaFunction(mainThread = true)
|
||||||
|
public final Object complex() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getType() {
|
public String getType() {
|
||||||
return "main_thread";
|
return "main_thread";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user