mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-07-06 20:12:52 +00:00

When creating a peripheral or custom Lua object, one must implement two methods: - getMethodNames(): String[] - Returns the name of the methods - callMethod(int, ...): Object[] - Invokes the method using an index in the above array. This has a couple of problems: - It's somewhat unwieldy to use - you need to keep track of array indices, which leads to ugly code. - Functions which yield (for instance, those which run on the main thread) are blocking. This means we need to spawn new threads for each CC-side yield. We replace this system with a few changes: - @LuaFunction annotation: One may annotate a public instance method with this annotation. This then exposes a peripheral/lua object method. Furthermore, this method can accept and return a variety of types, which often makes functions cleaner (e.g. can return an int rather than an Object[], and specify and int argument rather than Object[]). - MethodResult: Instead of returning an Object[] and having blocking yields, functions return a MethodResult. This either contains an immediate return, or an instruction to yield with some continuation to resume with. MethodResult is then interpreted by the Lua runtime (i.e. Cobalt), rather than our weird bodgey hacks before. This means we no longer spawn new threads when yielding within CC. - Methods accept IArguments instead of a raw Object array. This has a few benefits: - Consistent argument handling - people no longer need to use ArgumentHelper (as it doesn't exist!), or even be aware of its existence - you're rather forced into using it. - More efficient code in some cases. We provide a Cobalt-specific implementation of IArguments, which avoids the boxing/unboxing when handling numbers and binary strings.
171 lines
6.3 KiB
Java
171 lines
6.3 KiB
Java
/*
|
|
* This file is part of the public ComputerCraft API - http://www.computercraft.info
|
|
* Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only.
|
|
* For help using the API, and posting your mods, visit the forums at computercraft.info.
|
|
*/
|
|
package dan200.computercraft.api.lua;
|
|
|
|
import dan200.computercraft.api.peripheral.IComputerAccess;
|
|
|
|
import javax.annotation.Nonnull;
|
|
import javax.annotation.Nullable;
|
|
import java.nio.ByteBuffer;
|
|
import java.util.Collection;
|
|
import java.util.Map;
|
|
import java.util.Objects;
|
|
|
|
/**
|
|
* The result of invoking a Lua method.
|
|
*
|
|
* Method results either return a value immediately ({@link #of(Object...)} or yield control to the parent coroutine.
|
|
* When the current coroutine is resumed, we invoke the provided {@link ILuaCallback#resume(Object[])} callback.
|
|
*/
|
|
public final class MethodResult
|
|
{
|
|
private static final MethodResult empty = new MethodResult( null, null );
|
|
|
|
private final Object[] result;
|
|
private final ILuaCallback callback;
|
|
private final int adjust;
|
|
|
|
private MethodResult( Object[] arguments, ILuaCallback callback )
|
|
{
|
|
this.result = arguments;
|
|
this.callback = callback;
|
|
this.adjust = 0;
|
|
}
|
|
|
|
private MethodResult( Object[] arguments, ILuaCallback callback, int adjust )
|
|
{
|
|
this.result = arguments;
|
|
this.callback = callback;
|
|
this.adjust = adjust;
|
|
}
|
|
|
|
/**
|
|
* Return no values immediately.
|
|
*
|
|
* @return A method result which returns immediately with no values.
|
|
*/
|
|
@Nonnull
|
|
public static MethodResult of()
|
|
{
|
|
return empty;
|
|
}
|
|
|
|
/**
|
|
* Return a single value immediately.
|
|
*
|
|
* Integers, doubles, floats, strings, booleans, {@link Map}, {@link Collection}s, arrays and {@code null} will be
|
|
* converted to their corresponding Lua type. {@code byte[]} and {@link ByteBuffer} will be treated as binary
|
|
* strings.
|
|
*
|
|
* In order to provide a custom object with methods, one may return a {@link IDynamicLuaObject}, or an arbitrary
|
|
* class with {@link LuaFunction} annotations. Anything else will be converted to {@code nil}.
|
|
*
|
|
* @param value The value to return to the calling Lua function.
|
|
* @return A method result which returns immediately with the given value.
|
|
*/
|
|
@Nonnull
|
|
public static MethodResult of( @Nullable Object value )
|
|
{
|
|
return new MethodResult( new Object[] { value }, null );
|
|
}
|
|
|
|
/**
|
|
* Return any number of values immediately.
|
|
*
|
|
* @param values The values to return. See {@link #of(Object)} for acceptable values.
|
|
* @return A method result which returns immediately with the given values.
|
|
*/
|
|
@Nonnull
|
|
public static MethodResult of( @Nullable Object... values )
|
|
{
|
|
return values == null || values.length == 0 ? empty : new MethodResult( values, null );
|
|
}
|
|
|
|
/**
|
|
* Wait for an event to occur on the computer, suspending the thread until it arises. This method is exactly
|
|
* equivalent to {@code os.pullEvent()} in lua.
|
|
*
|
|
* @param filter A specific event to wait for, or null to wait for any event.
|
|
* @param callback The callback to resume with the name of the event that occurred, and any event parameters.
|
|
* @return The method result which represents this yield.
|
|
* @see IComputerAccess#queueEvent(String, Object[])
|
|
*/
|
|
@Nonnull
|
|
public static MethodResult pullEvent( @Nullable String filter, @Nonnull ILuaCallback callback )
|
|
{
|
|
Objects.requireNonNull( callback, "callback cannot be null" );
|
|
return new MethodResult( new Object[] { filter }, results -> {
|
|
if( results.length >= 1 && results[0].equals( "terminate" ) ) throw new LuaException( "Terminated", 0 );
|
|
return callback.resume( results );
|
|
} );
|
|
}
|
|
|
|
/**
|
|
* The same as {@link #pullEvent(String, ILuaCallback)}, except "terminated" events are ignored. Only use this if
|
|
* you want to prevent program termination, which is not recommended. This method is exactly equivalent to
|
|
* {@code os.pullEventRaw()} in Lua.
|
|
*
|
|
* @param filter A specific event to wait for, or null to wait for any event.
|
|
* @param callback The callback to resume with the name of the event that occurred, and any event parameters.
|
|
* @return The method result which represents this yield.
|
|
* @see #pullEvent(String, ILuaCallback)
|
|
*/
|
|
@Nonnull
|
|
public static MethodResult pullEventRaw( @Nullable String filter, @Nonnull ILuaCallback callback )
|
|
{
|
|
Objects.requireNonNull( callback, "callback cannot be null" );
|
|
return new MethodResult( new Object[] { filter }, callback );
|
|
}
|
|
|
|
/**
|
|
* Yield the current coroutine with some arguments until it is resumed. This method is exactly equivalent to
|
|
* {@code coroutine.yield()} in lua. Use {@code pullEvent()} if you wish to wait for events.
|
|
*
|
|
* @param arguments An object array containing the arguments to pass to coroutine.yield()
|
|
* @param callback The callback to resume with an array containing the return values from coroutine.yield()
|
|
* @return The method result which represents this yield.
|
|
* @see #pullEvent(String, ILuaCallback)
|
|
*/
|
|
@Nonnull
|
|
public static MethodResult yield( @Nullable Object[] arguments, @Nonnull ILuaCallback callback )
|
|
{
|
|
Objects.requireNonNull( callback, "callback cannot be null" );
|
|
return new MethodResult( arguments, callback );
|
|
}
|
|
|
|
@Nullable
|
|
public Object[] getResult()
|
|
{
|
|
return result;
|
|
}
|
|
|
|
@Nullable
|
|
public ILuaCallback getCallback()
|
|
{
|
|
return callback;
|
|
}
|
|
|
|
public int getErrorAdjust()
|
|
{
|
|
return adjust;
|
|
}
|
|
|
|
/**
|
|
* Increase the Lua error by a specific amount. One should never need to use this function - it largely exists for
|
|
* some CC internal code.
|
|
*
|
|
* @param adjust The amount to increase the level by.
|
|
* @return The new {@link MethodResult} with an adjusted error. This has no effect on immediate results.
|
|
*/
|
|
@Nonnull
|
|
public MethodResult adjustError( int adjust )
|
|
{
|
|
if( adjust < 0 ) throw new IllegalArgumentException( "cannot adjust by a negative amount" );
|
|
if( adjust == 0 || callback == null ) return this;
|
|
return new MethodResult( result, callback, this.adjust + adjust );
|
|
}
|
|
}
|