package io.gitlab.jfronny.libjf.config.plugin.asm.value; import io.gitlab.jfronny.libjf.config.plugin.asm.ConfigInjectClassTransformer; import io.gitlab.jfronny.libjf.config.plugin.util.GeneratorAdapter2; import org.objectweb.asm.Type; import org.objectweb.asm.commons.Method; import static io.gitlab.jfronny.libjf.config.plugin.asm.value.KnownTypes.*; import static org.objectweb.asm.Opcodes.ACC_PRIVATE; import static org.objectweb.asm.Opcodes.ACC_STATIC; import static org.objectweb.asm.Type.*; public class DiscoveredValue { private static final String PREFIX = ConfigInjectClassTransformer.PREFIX; public final String name; public final double min; public final double max; public final Type aType; public final KnownType type; public DiscoveredValue(String name, double min, double max, Type type) { this.name = name; this.min = min; this.max = max; this.aType = type; this.type = KnownType.of(type); } public void generateRegistration(GeneratorAdapter2 m, ConfigInjectClassTransformer t) { if (type != KnownType.OBJECT) { m.push(name); m.getStatic(t.current, name, aType); if (!aType.equals(type.unboxed)) { m.comment("Unboxing value " + name + " from " + aType + " to " + type.unboxed); m.unbox(type.unboxed); // Unbox (as parameter is unboxed) or leave as is (if target is unboxed) } } switch (type) { case INT, LONG, FLOAT, DOUBLE -> { m.comment("Numeric type"); m.push(min); m.push(max); m.supplier(t.current.getInternalName(), gName(), gDesc()); m.consumer(t.current.getInternalName(), sName(), sDesc()); t.dslInvoke(m, "value", CATEGORY_BUILDER_TYPE, STRING_TYPE, type.unboxed, DOUBLE_TYPE, DOUBLE_TYPE, SUPPLIER_TYPE, CONSUMER_TYPE); } case BOOLEAN, STRING -> { m.comment("Simple one-value type"); m.supplier(t.current.getInternalName(), gName(), gDesc()); m.consumer(t.current.getInternalName(), sName(), sDesc()); t.dslInvoke(m, "value", CATEGORY_BUILDER_TYPE, STRING_TYPE, type.unboxed, SUPPLIER_TYPE, CONSUMER_TYPE); } case OBJECT -> { System.err.println("WARNING: Attempted to use unsupported type in config. The entry \"" + name + "\" will fall back to reflective runtime access!"); m.comment("Reflective access due to missing compatibility for the type \"" + aType + "\""); m.push(t.current); m.push(name); m.invokeIStatic(ENTRY_INFO_TYPE, new Method("ofField", ENTRY_INFO_TYPE, new Type[]{CLASS_TYPE, STRING_TYPE})); m.invokeInterface(CATEGORY_BUILDER_TYPE, new Method("value", CATEGORY_BUILDER_TYPE, new Type[]{ENTRY_INFO_TYPE})); } } } public void generateλ(ConfigInjectClassTransformer t) { GeneratorAdapter2 m = t.method(ACC_PRIVATE | ACC_STATIC, gName(), gDesc().getInternalName(), null, null); m.getStatic(t.current, name, aType); m.comment("Boxing from " + aType + " (" + aType.getSort() + ")"); m.box(aType); // Box if target field uses unboxed value m.returnValue(); m.endMethod(); m = t.method(ACC_PRIVATE | ACC_STATIC, sName(), sDesc().getInternalName(), null, null); m.loadArg(0); m.unbox(aType); // Unbox to the target fields type m.putStatic(t.current, name, aType); m.returnValue(); m.endMethod(); } private String gName() { return PREFIX + "get$" + name; } private Type gDesc() { return getMethodType(type.boxed); } private String sName() { return PREFIX + "set$" + name; } private Type sDesc() { return getMethodType(VOID_TYPE, type.boxed); } }