From a46e948b5a0cf9bc8d31f557e371cd7d7c2f5b1c Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Tue, 24 Oct 2023 22:30:12 +0200 Subject: [PATCH] feat: Add `PatchOption#valueType` to handle type erasure Without this new property, it is not possible to infer the type without abusing `ClassCastException` at runtime to infer the type of the option value. BREAKING CHANGE: This changes the signature of the `PatchOption` constructor. --- api/revanced-patcher.api | 3 +- .../patcher/patch/options/PatchOption.kt | 42 ++++++++++++++----- .../patcher/patch/options/PatchOptionsTest.kt | 4 ++ 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/api/revanced-patcher.api b/api/revanced-patcher.api index 2047f55..ecb12e4 100644 --- a/api/revanced-patcher.api +++ b/api/revanced-patcher.api @@ -289,7 +289,7 @@ public abstract interface annotation class app/revanced/patcher/patch/annotation public class app/revanced/patcher/patch/options/PatchOption { public static final field PatchExtensions Lapp/revanced/patcher/patch/options/PatchOption$PatchExtensions; - public fun (Ljava/lang/String;Ljava/lang/Object;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLkotlin/jvm/functions/Function2;)V + public fun (Ljava/lang/String;Ljava/lang/Object;Ljava/util/Map;Ljava/lang/String;Ljava/lang/String;ZLjava/lang/String;Lkotlin/jvm/functions/Function2;)V public final fun getDefault ()Ljava/lang/Object; public final fun getDescription ()Ljava/lang/String; public final fun getKey ()Ljava/lang/String; @@ -298,6 +298,7 @@ public class app/revanced/patcher/patch/options/PatchOption { public final fun getValidator ()Lkotlin/jvm/functions/Function2; public final fun getValue ()Ljava/lang/Object; public final fun getValue (Ljava/lang/Object;Lkotlin/reflect/KProperty;)Ljava/lang/Object; + public final fun getValueType ()Ljava/lang/String; public final fun getValues ()Ljava/util/Map; public fun reset ()V public final fun setValue (Ljava/lang/Object;)V diff --git a/src/main/kotlin/app/revanced/patcher/patch/options/PatchOption.kt b/src/main/kotlin/app/revanced/patcher/patch/options/PatchOption.kt index 923f0af..d9522ec 100644 --- a/src/main/kotlin/app/revanced/patcher/patch/options/PatchOption.kt +++ b/src/main/kotlin/app/revanced/patcher/patch/options/PatchOption.kt @@ -12,6 +12,7 @@ import kotlin.reflect.KProperty * @param title The title. * @param description A description. * @param required Whether the option is required. + * @param valueType The type of the option value (to handle type erasure). * @param validator The function to validate the option value. * @param T The value type of the option. */ @@ -23,6 +24,7 @@ open class PatchOption( val title: String?, val description: String?, val required: Boolean, + val valueType: String, val validator: PatchOption.(T?) -> Boolean ) { /** @@ -110,7 +112,9 @@ open class PatchOption( description: String? = null, required: Boolean = false, validator: PatchOption.(String?) -> Boolean = { true } - ) = PatchOption(key, default, values, title, description, required, validator).also { registerOption(it) } + ) = PatchOption( + key, default, values, title, description, required, "String", validator + ).also { registerOption(it) } /** * Create a new [PatchOption] with an integer value and add it to the current [Patch]. @@ -135,7 +139,9 @@ open class PatchOption( description: String? = null, required: Boolean = false, validator: PatchOption.(Int?) -> Boolean = { true } - ) = PatchOption(key, default, values, title, description, required, validator).also { registerOption(it) } + ) = PatchOption( + key, default, values, title, description, required, "Int", validator + ).also { registerOption(it) } /** * Create a new [PatchOption] with a boolean value and add it to the current [Patch]. @@ -160,7 +166,9 @@ open class PatchOption( description: String? = null, required: Boolean = false, validator: PatchOption.(Boolean?) -> Boolean = { true } - ) = PatchOption(key, default, values, title, description, required, validator).also { registerOption(it) } + ) = PatchOption(key, default, values, title, description, required, "Boolean", validator).also { + registerOption(it) + } /** * Create a new [PatchOption] with a float value and add it to the current [Patch]. @@ -185,7 +193,9 @@ open class PatchOption( description: String? = null, required: Boolean = false, validator: PatchOption.(Float?) -> Boolean = { true } - ) = PatchOption(key, default, values, title, description, required, validator).also { registerOption(it) } + ) = PatchOption( + key, default, values, title, description, required, "Float", validator + ).also { registerOption(it) } /** * Create a new [PatchOption] with a long value and add it to the current [Patch]. @@ -210,7 +220,9 @@ open class PatchOption( description: String? = null, required: Boolean = false, validator: PatchOption.(Long?) -> Boolean = { true } - ) = PatchOption(key, default, values, title, description, required, validator).also { registerOption(it) } + ) = PatchOption( + key, default, values, title, description, required, "Long", validator + ).also { registerOption(it) } /** * Create a new [PatchOption] with a string array value and add it to the current [Patch]. @@ -235,7 +247,9 @@ open class PatchOption( description: String? = null, required: Boolean = false, validator: PatchOption?>.(Array?) -> Boolean = { true } - ) = PatchOption(key, default, values, title, description, required, validator).also { registerOption(it) } + ) = PatchOption( + key, default, values, title, description, required, "StringArray", validator + ).also { registerOption(it) } /** * Create a new [PatchOption] with an integer array value and add it to the current [Patch]. @@ -260,7 +274,9 @@ open class PatchOption( description: String? = null, required: Boolean = false, validator: PatchOption?>.(Array?) -> Boolean = { true } - ) = PatchOption(key, default, values, title, description, required, validator).also { registerOption(it) } + ) = PatchOption( + key, default, values, title, description, required, "IntArray", validator + ).also { registerOption(it) } /** * Create a new [PatchOption] with a boolean array value and add it to the current [Patch]. @@ -285,7 +301,9 @@ open class PatchOption( description: String? = null, required: Boolean = false, validator: PatchOption?>.(Array?) -> Boolean = { true } - ) = PatchOption(key, default, values, title, description, required, validator).also { registerOption(it) } + ) = PatchOption( + key, default, values, title, description, required, "BooleanArray", validator + ).also { registerOption(it) } /** * Create a new [PatchOption] with a float array value and add it to the current [Patch]. @@ -310,7 +328,9 @@ open class PatchOption( description: String? = null, required: Boolean = false, validator: PatchOption?>.(Array?) -> Boolean = { true } - ) = PatchOption(key, default, values, title, description, required, validator).also { registerOption(it) } + ) = PatchOption( + key, default, values, title, description, required, "FloatArray", validator + ).also { registerOption(it) } /** * Create a new [PatchOption] with a long array value and add it to the current [Patch]. @@ -335,7 +355,9 @@ open class PatchOption( description: String? = null, required: Boolean = false, validator: PatchOption?>.(Array?) -> Boolean = { true } - ) = PatchOption(key, default, values, title, description, required, validator).also { registerOption(it) } + ) = PatchOption( + key, default, values, title, description, required, "LongArray", validator + ).also { registerOption(it) } private fun

> P.registerOption(option: PatchOption<*>) = option.also { options.register(it) } } diff --git a/src/test/kotlin/app/revanced/patcher/patch/options/PatchOptionsTest.kt b/src/test/kotlin/app/revanced/patcher/patch/options/PatchOptionsTest.kt index f982af9..943d91d 100644 --- a/src/test/kotlin/app/revanced/patcher/patch/options/PatchOptionsTest.kt +++ b/src/test/kotlin/app/revanced/patcher/patch/options/PatchOptionsTest.kt @@ -85,6 +85,10 @@ internal class PatchOptionsTest { } } + @Test + fun `option types should be known`() = + assertTrue(OptionsTestPatch.options["array"].valueType == "StringArray") + @Test fun `getting default value should work`() = assertDoesNotThrow { assertNull(OptionsTestPatch.resettableOption.default) }