Use a builder for constructing ComputerContexts

We've got a few optional fields here, and more on their way, so this
ends up being a little nicer.
This commit is contained in:
Jonathan Coates 2023-06-26 18:42:19 +01:00
parent 4accda6b8e
commit bc500df921
No known key found for this signature in database
GPG Key ID: B9E431FF07C98D06
5 changed files with 99 additions and 33 deletions

View File

@ -9,7 +9,6 @@
import dan200.computercraft.api.filesystem.Mount;
import dan200.computercraft.api.network.PacketNetwork;
import dan200.computercraft.core.ComputerContext;
import dan200.computercraft.core.computer.ComputerThread;
import dan200.computercraft.core.computer.GlobalEnvironment;
import dan200.computercraft.core.computer.mainthread.MainThread;
import dan200.computercraft.core.computer.mainthread.MainThreadConfig;
@ -67,11 +66,11 @@ private ServerContext(MinecraftServer server) {
this.server = server;
storageDir = server.getWorldPath(FOLDER);
mainThread = new MainThread(mainThreadConfig);
context = new ComputerContext(
new Environment(server),
new ComputerThread(ConfigSpec.computerThreads.get()),
mainThread, luaMachine
);
context = ComputerContext.builder(new Environment(server))
.computerThreads(ConfigSpec.computerThreads.get())
.mainThreadScheduler(mainThread)
.luaFactory(luaMachine)
.build();
idAssigner = new IDAssigner(storageDir.resolve("ids.json"));
}

View File

@ -7,10 +7,13 @@
import dan200.computercraft.core.computer.ComputerThread;
import dan200.computercraft.core.computer.GlobalEnvironment;
import dan200.computercraft.core.computer.mainthread.MainThreadScheduler;
import dan200.computercraft.core.computer.mainthread.NoWorkMainThreadScheduler;
import dan200.computercraft.core.lua.CobaltLuaMachine;
import dan200.computercraft.core.lua.ILuaMachine;
import javax.annotation.CheckReturnValue;
import javax.annotation.Nullable;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
/**
@ -20,27 +23,16 @@ public final class ComputerContext {
private final GlobalEnvironment globalEnvironment;
private final ComputerThread computerScheduler;
private final MainThreadScheduler mainThreadScheduler;
private final ILuaMachine.Factory factory;
private final ILuaMachine.Factory luaFactory;
public ComputerContext(
ComputerContext(
GlobalEnvironment globalEnvironment, ComputerThread computerScheduler,
MainThreadScheduler mainThreadScheduler, ILuaMachine.Factory factory
MainThreadScheduler mainThreadScheduler, ILuaMachine.Factory luaFactory
) {
this.globalEnvironment = globalEnvironment;
this.computerScheduler = computerScheduler;
this.mainThreadScheduler = mainThreadScheduler;
this.factory = factory;
}
/**
* Create a default {@link ComputerContext} with the given global environment.
*
* @param environment The current global environment.
* @param threads The number of threads to use for the {@link #computerScheduler()}
* @param mainThreadScheduler The main thread scheduler to use.
*/
public ComputerContext(GlobalEnvironment environment, int threads, MainThreadScheduler mainThreadScheduler) {
this(environment, new ComputerThread(threads), mainThreadScheduler, CobaltLuaMachine::new);
this.luaFactory = luaFactory;
}
/**
@ -77,7 +69,7 @@ public MainThreadScheduler mainThreadScheduler() {
* @return The current Lua machine factory.
*/
public ILuaMachine.Factory luaFactory() {
return factory;
return luaFactory;
}
/**
@ -106,4 +98,85 @@ public void ensureClosed(long timeout, TimeUnit unit) throws InterruptedExceptio
throw new IllegalStateException("Failed to shutdown ComputerContext in time.");
}
}
/**
* Create a new {@linkplain Builder builder} for a computer context.
*
* @param environment The {@linkplain ComputerContext#globalEnvironment() global environment} for this context.
* @return The builder for a new context.
*/
public static Builder builder(GlobalEnvironment environment) {
return new Builder(environment);
}
/**
* A builder for a {@link ComputerContext}.
*
* @see ComputerContext#builder(GlobalEnvironment)
*/
public static class Builder {
private final GlobalEnvironment environment;
private int threads = 1;
private @Nullable MainThreadScheduler mainThreadScheduler;
private @Nullable ILuaMachine.Factory luaFactory;
Builder(GlobalEnvironment environment) {
this.environment = environment;
}
/**
* Set the number of threads the {@link ComputerThread} will use.
*
* @param threads The number of threads to use.
* @return {@code this}, for chaining
* @see ComputerContext#computerScheduler()
*/
public Builder computerThreads(int threads) {
if (threads < 1) throw new IllegalArgumentException("Threads must be >= 1");
this.threads = threads;
return this;
}
/**
* Set the {@link MainThreadScheduler} for this context.
*
* @param scheduler The main thread scheduler.
* @return {@code this}, for chaining
* @see ComputerContext#mainThreadScheduler()
*/
public Builder mainThreadScheduler(MainThreadScheduler scheduler) {
Objects.requireNonNull(scheduler);
if (mainThreadScheduler != null) throw new IllegalStateException("Main-thread scheduler already specified");
mainThreadScheduler = scheduler;
return this;
}
/**
* Set the {@link ILuaMachine.Factory} for this context.
*
* @param factory The Lua machine factory.
* @return {@code this}, for chaining
* @see ComputerContext#luaFactory()
*/
public Builder luaFactory(ILuaMachine.Factory factory) {
Objects.requireNonNull(factory);
if (luaFactory != null) throw new IllegalStateException("Main-thread scheduler already specified");
luaFactory = factory;
return this;
}
/**
* Create a new {@link ComputerContext}.
*
* @return The newly created context.
*/
public ComputerContext build() {
return new ComputerContext(
environment,
new ComputerThread(threads),
mainThreadScheduler == null ? new NoWorkMainThreadScheduler() : mainThreadScheduler,
luaFactory == null ? CobaltLuaMachine::new : luaFactory
);
}
}
}

View File

@ -11,8 +11,6 @@
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.core.computer.Computer;
import dan200.computercraft.core.computer.ComputerSide;
import dan200.computercraft.core.computer.ComputerThread;
import dan200.computercraft.core.computer.mainthread.NoWorkMainThreadScheduler;
import dan200.computercraft.core.filesystem.FileSystemException;
import dan200.computercraft.core.filesystem.WritableFileMount;
import dan200.computercraft.core.lua.CobaltLuaMachine;
@ -112,7 +110,7 @@ public void before() throws IOException {
}
var environment = new BasicEnvironment(mount);
context = new ComputerContext(environment, new ComputerThread(1), new NoWorkMainThreadScheduler(), CoverageLuaMachine::new);
context = ComputerContext.builder(environment).luaFactory(CoverageLuaMachine::new).build();
computer = new Computer(context, environment, term, 0);
computer.getEnvironment().setPeripheral(ComputerSide.TOP, new FakeModem());
computer.getEnvironment().setPeripheral(ComputerSide.BOTTOM, new FakePeripheralHub());

View File

@ -49,7 +49,7 @@ public static void run(WritableMount mount, Consumer<Computer> setup, int maxTic
var term = new Terminal(51, 19, true);
var mainThread = new MainThread(new MainThreadConfig.Basic(Integer.MAX_VALUE, Integer.MAX_VALUE));
var environment = new BasicEnvironment(mount);
var context = new ComputerContext(environment, 1, mainThread);
var context = ComputerContext.builder(environment).mainThreadScheduler(mainThread).build();
final var computer = new Computer(context, environment, term, 0);
var api = new AssertApi();

View File

@ -7,9 +7,7 @@
import dan200.computercraft.api.lua.ILuaAPI
import dan200.computercraft.core.ComputerContext
import dan200.computercraft.core.computer.Computer
import dan200.computercraft.core.computer.ComputerThread
import dan200.computercraft.core.computer.TimeoutState
import dan200.computercraft.core.computer.mainthread.NoWorkMainThreadScheduler
import dan200.computercraft.core.lua.MachineEnvironment
import dan200.computercraft.core.lua.MachineResult
import dan200.computercraft.core.terminal.Terminal
@ -27,11 +25,9 @@
class KotlinComputerManager : AutoCloseable {
private val machines: MutableMap<Computer, Queue<FakeComputerTask>> = HashMap()
private val context = ComputerContext(
BasicEnvironment(),
ComputerThread(1),
NoWorkMainThreadScheduler(),
) { env, _ -> DummyLuaMachine(env) }
private val context = ComputerContext.builder(BasicEnvironment())
.luaFactory { env, _ -> DummyLuaMachine(env) }
.build()
private val errorLock: Lock = ReentrantLock()
private val hasError = errorLock.newCondition()