Skip to content

Commit

Permalink
feat: registry for patch options
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Patch options now use the PatchOptions registry class instead of an Iterable. This change requires modifications to existing patches using this API.
  • Loading branch information
Sculas committed Aug 2, 2022
1 parent fb3c0e8 commit 2431785
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 25 deletions.
2 changes: 1 addition & 1 deletion src/main/kotlin/app/revanced/patcher/patch/Patch.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ abstract class Patch<out T : Data> {
/**
* A list of [PatchOption]s.
*/
open val options: Iterable<PatchOption<*>> = listOf()
open val options = PatchOptions()
}
41 changes: 41 additions & 0 deletions src/main/kotlin/app/revanced/patcher/patch/PatchOption.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,46 @@
package app.revanced.patcher.patch

@Suppress("CanBeParameter", "MemberVisibilityCanBePrivate")
class NoSuchOptionException(val option: String) : Exception("No such option: $option")

/**
* A registry for an array of [PatchOption]s.
* @param options An array of [PatchOption]s.
*/
@Suppress("MemberVisibilityCanBePrivate")
class PatchOptions(vararg val options: PatchOption<*>) : Iterable<PatchOption<*>> {
private val register = buildMap {
for (option in options) {
if (containsKey(option.key)) {
throw IllegalStateException("Multiple options found with the same key")
}
put(option.key, option)
}
}

/**
* Get a [PatchOption] by its key.
* @param key The key of the [PatchOption].
*/
operator fun get(key: String) = register[key] ?: throw NoSuchOptionException(key)

/**
* Set the value of a [PatchOption].
* @param key The key of the [PatchOption].
* @param value The value you want it to be.
* Please note that using the wrong value type results in a runtime error.
*/
inline operator fun <reified T> set(key: String, value: T) {
@Suppress("UNCHECKED_CAST") val opt = get(key) as? PatchOption<T>
if (opt == null || opt.value !is T) throw IllegalArgumentException(
"The type of the option value is not the same as the type value provided"
)
opt.value = value
}

override fun iterator() = options.iterator()
}

/**
* A [Patch] option.
* @param key Unique identifier of the option. Example: _`settings.microg.enabled`_
Expand Down
45 changes: 26 additions & 19 deletions src/test/kotlin/app/revanced/patcher/usage/PatchOptionsUsage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,36 @@ package app.revanced.patcher.usage

import app.revanced.patcher.patch.PatchOption
import app.revanced.patcher.usage.bytecode.ExampleBytecodePatch
import kotlin.test.Test

fun patchOptionsUsage() {
val options = ExampleBytecodePatch().options
for (option in options) {
when (option) {
is PatchOption.StringOption -> {
option.value = "Hello World"
}
is PatchOption.BooleanOption -> {
option.value = false
}
is PatchOption.StringListOption -> {
option.value = option.options.first()
for (choice in option.options) {
println(choice)
internal class PatchOptionsUsage {
@Test
fun patchOptionsUsage() {
val options = ExampleBytecodePatch().options
for (option in options) {
when (option) {
is PatchOption.StringOption -> {
option.value = "Hello World"
}
}
is PatchOption.IntListOption -> {
option.value = option.options.first()
for (choice in option.options) {
println(choice)
is PatchOption.BooleanOption -> {
option.value = false
}
is PatchOption.StringListOption -> {
option.value = option.options.first()
for (choice in option.options) {
println(choice)
}
}
is PatchOption.IntListOption -> {
option.value = option.options.first()
for (choice in option.options) {
println(choice)
}
}
}
}
println(options["key1"].value)
options["key1"] = "Hello, world!"
println(options["key1"].value)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.or
import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patcher.patch.PatchOption
import app.revanced.patcher.patch.PatchOptions
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependencyType
Expand Down Expand Up @@ -164,18 +165,18 @@ class ExampleBytecodePatch : BytecodePatch(listOf(ExampleFingerprint)) {
)
}

override val options = listOf(
override val options = PatchOptions(
PatchOption.StringOption(
"key", "default", "title", "description", true
"key1", "default", "title", "description", true
),
PatchOption.BooleanOption(
"key", true, "title", "description" // required defaults to false
"key2", true, "title", "description" // required defaults to false
),
PatchOption.StringListOption(
"key", "TEST", listOf("TEST", "TEST1", "TEST2"), "title", "description"
"key3", "TEST", listOf("TEST", "TEST1", "TEST2"), "title", "description"
),
PatchOption.IntListOption(
"key", 1, listOf(1, 2, 3), "title", "description"
"key4", 1, listOf(1, 2, 3), "title", "description"
),
)
}

0 comments on commit 2431785

Please sign in to comment.