Files
fabric-carpet/src/main/java/carpet/script/annotation/OptionalConverter.java
T
altrisi cc7a9c01be Annotated Scarpet (#772)
* Progress by now.

* Output conversions plus a few extra random things

* More progress, mostly list converting and a way to get converters

* Apply ValueConverters, refactor valueconverter getter to

accept types with annotations and generics, made listconverter pass
those params and annotations recursively. And probably more things.

* Some extra docs, the 100% most important thing

* Added MapConverter, strict Strings and Texts, some docs additions

and commented out heuristics

* Rework StrictParam to use SimpleTypeConverters and be saved in a map

* Minor changes and docs & added non-fully-functional context "converter"

* Added support for variable value count converters, multi-value eaters &

0 value eaters (Context).

* Docs update, enable Context converter, fix minor TODOs

* Move (most) parameter annotations into a single class,

remove deprecated ValueCaster#cast, update some docs.

* Small refactor of Param.Strict registering, added boolean to it

* Added PairConverter, moved Context and LV ValueConverters to Params

* Document public methods of AnnotationParser

* Add a lot more docs, make it ready for the first preview PR

* Move ValueConverter population outside of makeFunction,

check lv size for > max arguments, minor doc updates and workaround for
Mercury#28 until released

* Added optional parameters (declared using Java's Optional),

made evalAndConvert check for the presence of the next iteration,
updated test class

* Generalize Value OutputConverter

* ListConverter and MapConverter now follow ValueConverter contract of

incorrect value handling, returning a complete null for an incorrect
value anywhere. Also small fix to OptionalConverter and docs.
Getting ready for checking null in AnnotationParser!

* Change reflection's #invoke to a MethodHandle to boost speed by a lot

Commented

* Dedupe code, update and remove outdated todos, add 2 new ValueCasters

* Merge lambdas in display_title2 test function to be more accurate

* Check nulls somehow, I guess

* Move base function logic into a class to stop

passing hundreds of parameters into static functions and therefore simplify it

* Reduce visibility and fix a bug with PairConverter

* Hide Context provider in usage report

* Add support for primitive varargs

* Added TheLazyT converter

* Drop #getPrefixedTypeName and use 'something' as name of values

* Use value again because of varargs, document that

* Remove a completed TODO

* Remove old disabled heuristic value type name getter

* Fix TheLazyT

* Preparing locators before touching current Carpet infrastructure

* Add notes about non-implementedness of remaining locators

* Added APIs to register custom ValueConverters

* Mention new APIs in javadocs

* Adapt to new Carpet changes and deprecated non-implemented annotations

* Update example function for display_title()

* Better implementation for player_list example

* Fix example error message

* FunctionArgument no longer has generics

* Modernize Text converters

* OutputConverter is final, plus other small changes

* Few non-behavioural changes

* Rename LazyFunction to ScarpetFunction

* Drop LazyValue in parameters, not in return

Updating docs was a nightmare

* CARPET CHANGE - Make Fluff.AbstractLazyFunction.unpackArgs call unpackLazy (was duped)

* Make errors more like current Scarpet errors

* Allow customizing ContextType when evaluating arguments

* Add a few missing docs, comment out outdated ValueCaster doc

It's been a while, wow

* Fix for new Carpet signature :irritatered:

Please don't break API methods! Extensions may be using them, and they
will just crash the game or behave in unexpected ways else!

* Format all code to Carpet's. Powered by Eclipse

Reviewed to be sure it's ok. No functional changes, except from a small correction

* Always use full name for Context.Type

* Add parsing for all current Scarpet api and language classes

And remove test functions

* Allow void return type

* Fix no param methods

Whoops!

* Remove outdated comment and fix small javadoc linting problem

* Drop Param.TheLazyT in favour of just Context.Type type

And small performance improvement to varargs varargs since fastutil's toArray is crap

* Quote functions in error messages

* Make SimpleTypeConverter independent of ValueCaster

'Real world' usage demonstrated it can be annoying else, mostly for wrapper only values where you just want the wrapped object
2021-05-21 01:33:00 -03:00

108 lines
4.3 KiB
Java

package carpet.script.annotation;
import java.lang.reflect.AnnotatedParameterizedType;
import java.lang.reflect.AnnotatedType;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.Optional;
import carpet.script.Context;
import carpet.script.value.Value;
/**
* <p>{@link ValueConverter} that accepts a parameter to not be present on function call.</p>
*
* <p>Note that it will not work properly if it's not at the end of the function, since values are consumed in an ordered way, therefore it will throw
* if the value is not present since it will try to evaluate the next parameter into {@code <R>} and horribly fail, or it will draw values from the
* {@link ValueConverter}s after it, horribly failing too..</p>
*
* <p>Why {@link Optional}?</p>
*
* <p>It allows passing three states:</p>
* <ul>
* <li>A wrapped object, if the value was present and correct</li>
* <li>An incorrect value ({@code null}), if the value was present but incorrect, as per the contract of {@link ValueConverter} and the way
* {@link AnnotationParser} will consider {@link null} values</li>
* <li>An empty {@link Optional}, if the value was not present (or {@code null})</li>
* </ul>
*
* @param <R> The type of the internal {@link ValueConverter}, basically the generic type of the {@link Optional}
*/
final class OptionalConverter<R> implements ValueConverter<Optional<R>>
{
private final ValueConverter<R> typeConverter;
@Override
public String getTypeName()
{
return "optional " + typeConverter.getTypeName();
}
private OptionalConverter(AnnotatedType type)
{
typeConverter = ValueConverter.fromAnnotatedType(type);
}
/**
* {@inheritDoc}
*
* @implNote Unlike most other converters, {@link OptionalConverter} will not call this method from
* {@link #checkAndConvert(Iterator, Context, Context.Type)} and is only used as a fallback in types that don't support it.
*/
@Override
public Optional<R> convert(Value value)
{
if (value.isNull())
return Optional.empty();
R converted = typeConverter.convert(value);
if (converted == null)
return null;
return Optional.of(converted);
}
@Override
public Optional<R> checkAndConvert(Iterator<Value> valueIterator, Context context, Context.Type theLazyT)
{
if (!valueIterator.hasNext() || valueIterator.next().isNull())
return Optional.empty();
((ListIterator<Value>) valueIterator).previous();
R converted = typeConverter.checkAndConvert(valueIterator, context, theLazyT);
if (converted == null)
return null;
return Optional.of(converted);
}
@Override
public boolean consumesVariableArgs()
{
return true;
}
@Override
public int valueConsumption()
{
return 0; // Optional parameters therefore require a minimum of 0
}
/**
* <p>Returns a new {@link OptionalConverter} to convert to the type in the given {@link AnnotatedType} if there is at least one element left in
* the iterator, with any parameters, annotations or anything that was present in there.</p>
*
* <p>The given {@link ValueConverter} will be called after ensuring that there is at least one element left in the iterator to the type specified
* in the generics of this {@link AnnotatedType}, or return an empty {@link Optional} if there is nothing left or the first value meets
* {@link Value#isNull()}.
*
* @apiNote This method expects the {@link AnnotatedType} to already be of {@link Optional} type, and, while it will technically accept a
* non-{@link Optional} {@link AnnotatedType}, it will fail with an {@link ArrayIndexOutOfBoundsException} if it doesn't has at least one
* generic parameter.
* @param annotatedType The type to get generics information from
* @return A new {@link OptionalConverter} for the data specified in the {@link AnnotatedType}
*/
static OptionalConverter<?> fromAnnotatedType(AnnotatedType annotatedType)
{
AnnotatedParameterizedType paramType = (AnnotatedParameterizedType) annotatedType;
AnnotatedType wrappedType = paramType.getAnnotatedActualTypeArguments()[0];
return new OptionalConverter<>(wrappedType);
}
}