package carpet.script.annotation;
import java.util.HashMap;
import java.util.Map;
import carpet.script.value.AbstractListValue;
import carpet.script.value.BlockValue;
import carpet.script.value.BooleanValue;
import carpet.script.value.EntityValue;
import carpet.script.value.FormattedTextValue;
import carpet.script.value.FunctionValue;
import carpet.script.value.ListValue;
import carpet.script.value.MapValue;
import carpet.script.value.NBTSerializableValue;
import carpet.script.value.NumericValue;
import carpet.script.value.StringValue;
import carpet.script.value.ThreadValue;
import carpet.script.value.Value;
/**
*
Simple {@link ValueConverter} implementation that casts a {@link Value} into one of its subclasses, either for use directly in parameters or
* converters, or as an already working middle step.
*
* {@link ValueCaster}s are reused whenever asked for one, since they don't have any complexity.
*
* @see #register(Class, String)
*
* @param The {@link Value} subclass this {@link ValueCaster} casts to
*/
public final class ValueCaster implements ValueConverter // R always extends Value, not explicitly because of type checking
{
private static final Map, ValueCaster extends Value>> byResult = new HashMap<>();
static
{
register(Value.class, "value");
register(BlockValue.class, "block");
register(EntityValue.class, "entity");
register(FormattedTextValue.class, "formatted text");
register(FunctionValue.class, "function");
register(ListValue.class, "list");
register(MapValue.class, "map");
register(AbstractListValue.class, "list or similar"); // For LazyListValue basically? Not sure what should use this
register(NBTSerializableValue.class, "nbt object");
register(NumericValue.class, "number");
register(BooleanValue.class, "boolean");
register(StringValue.class, "string");
register(ThreadValue.class, "thread");
}
private final Class outputType;
private final String typeName;
private ValueCaster(Class outputType, String typeName)
{
this.outputType = outputType;
this.typeName = typeName;
}
@Override
public String getTypeName()
{
return typeName;
}
/**
* Returns the registered {@link ValueCaster} for the specified outputType.
*
* @param The type of the {@link ValueCaster} you are looking for
* @param outputType The class of the {@link Value} the returned {@link ValueCaster} casts to
* @return The {@link ValueCaster} for the specified outputType
*/
@SuppressWarnings("unchecked") // Casters are stored with their exact class, for sure since the map is private (&& class has same generic as
// caster)
public static ValueCaster get(Class outputType)
{
return (ValueCaster) byResult.get(outputType);
}
@Override
public R convert(Value value)
{
if (!outputType.isInstance(value))
return null;
return outputType.cast(value);
}
/**
* Registers a new {@link Value} to be able to use it in {@link SimpleTypeConverter}
*
* @param The {@link Value} subclass
* @param valueClass The class of T
* @param typeName A {@link String} representing the name of this type. It will be used in error messages when there is no higher type
* required
*/
public static void register(Class valueClass, String typeName)
{
ValueCaster caster = new ValueCaster(valueClass, typeName);
byResult.putIfAbsent(valueClass, caster);
}
}