Skip to content

Commit

Permalink
Merge pull request #731 from arkivanov/unique-configs
Browse files Browse the repository at this point in the history
Allow duplicate configurations as an experimental feature
  • Loading branch information
arkivanov authored Jul 1, 2024
2 parents 58c27a0 + a504a8f commit ce4d007
Show file tree
Hide file tree
Showing 26 changed files with 773 additions and 128 deletions.
24 changes: 20 additions & 4 deletions decompose/api/android/decompose.api
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,39 @@ public abstract interface class com/arkivanov/decompose/Cancellation {
public abstract class com/arkivanov/decompose/Child {
public abstract fun getConfiguration ()Ljava/lang/Object;
public abstract fun getInstance ()Ljava/lang/Object;
public abstract fun getKey ()Ljava/lang/Object;
}

public final class com/arkivanov/decompose/Child$Created : com/arkivanov/decompose/Child {
public fun <init> (Ljava/lang/Object;Ljava/lang/Object;)V
public fun <init> (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V
public final fun component1 ()Ljava/lang/Object;
public final fun component2 ()Ljava/lang/Object;
public final fun copy (Ljava/lang/Object;Ljava/lang/Object;)Lcom/arkivanov/decompose/Child$Created;
public static synthetic fun copy$default (Lcom/arkivanov/decompose/Child$Created;Ljava/lang/Object;Ljava/lang/Object;ILjava/lang/Object;)Lcom/arkivanov/decompose/Child$Created;
public final fun component3 ()Ljava/lang/Object;
public final synthetic fun copy (Ljava/lang/Object;Ljava/lang/Object;)Lcom/arkivanov/decompose/Child;
public final fun copy (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Lcom/arkivanov/decompose/Child$Created;
public static synthetic fun copy$default (Lcom/arkivanov/decompose/Child$Created;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;ILjava/lang/Object;)Lcom/arkivanov/decompose/Child$Created;
public fun equals (Ljava/lang/Object;)Z
public fun getConfiguration ()Ljava/lang/Object;
public fun getInstance ()Ljava/lang/Object;
public fun getKey ()Ljava/lang/Object;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class com/arkivanov/decompose/Child$Destroyed : com/arkivanov/decompose/Child {
public fun <init> (Ljava/lang/Object;)V
public fun <init> (Ljava/lang/Object;Ljava/lang/Object;)V
public final fun component1 ()Ljava/lang/Object;
public final fun copy (Ljava/lang/Object;)Lcom/arkivanov/decompose/Child$Destroyed;
public static synthetic fun copy$default (Lcom/arkivanov/decompose/Child$Destroyed;Ljava/lang/Object;ILjava/lang/Object;)Lcom/arkivanov/decompose/Child$Destroyed;
public final fun component2 ()Ljava/lang/Object;
public final synthetic fun copy (Ljava/lang/Object;)Lcom/arkivanov/decompose/Child;
public final fun copy (Ljava/lang/Object;Ljava/lang/Object;)Lcom/arkivanov/decompose/Child$Destroyed;
public static synthetic fun copy$default (Lcom/arkivanov/decompose/Child$Destroyed;Ljava/lang/Object;Ljava/lang/Object;ILjava/lang/Object;)Lcom/arkivanov/decompose/Child$Destroyed;
public fun equals (Ljava/lang/Object;)Z
public fun getConfiguration ()Ljava/lang/Object;
public synthetic fun getInstance ()Ljava/lang/Object;
public fun getInstance ()Ljava/lang/Void;
public fun getKey ()Ljava/lang/Object;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}
Expand All @@ -49,6 +58,12 @@ public abstract interface class com/arkivanov/decompose/ComponentContextFactoryO
public abstract fun getComponentContextFactory ()Lcom/arkivanov/decompose/ComponentContextFactory;
}

public final class com/arkivanov/decompose/DecomposeExperimentFlags {
public static final field INSTANCE Lcom/arkivanov/decompose/DecomposeExperimentFlags;
public final fun getDuplicateConfigurationsEnabled ()Z
public final fun setDuplicateConfigurationsEnabled (Z)V
}

public final class com/arkivanov/decompose/DeeplinkUtilsKt {
public static final fun handleDeepLink (Landroid/app/Activity;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
}
Expand Down Expand Up @@ -270,6 +285,7 @@ public final class com/arkivanov/decompose/router/stack/ChildStack {
public fun <init> (Lcom/arkivanov/decompose/Child$Created;Ljava/util/List;)V
public synthetic fun <init> (Lcom/arkivanov/decompose/Child$Created;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Ljava/lang/Object;Ljava/lang/Object;)V
public fun <init> (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V
public final fun component1 ()Lcom/arkivanov/decompose/Child$Created;
public final fun component2 ()Ljava/util/List;
public final fun copy (Lcom/arkivanov/decompose/Child$Created;Ljava/util/List;)Lcom/arkivanov/decompose/router/stack/ChildStack;
Expand Down
22 changes: 20 additions & 2 deletions decompose/api/decompose.klib.api
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ final class <#A: out kotlin/Any, #B: out kotlin/Any> com.arkivanov.decompose.rou
}
final class <#A: out kotlin/Any, #B: out kotlin/Any> com.arkivanov.decompose.router.stack/ChildStack { // com.arkivanov.decompose.router.stack/ChildStack|null[0]
constructor <init>(#A, #B) // com.arkivanov.decompose.router.stack/ChildStack.<init>|<init>(1:0;1:1){}[0]
constructor <init>(#A, #B, kotlin/Any) // com.arkivanov.decompose.router.stack/ChildStack.<init>|<init>(1:0;1:1;kotlin.Any){}[0]
constructor <init>(com.arkivanov.decompose/Child.Created<#A, #B>, kotlin.collections/List<com.arkivanov.decompose/Child.Created<#A, #B>> = ...) // com.arkivanov.decompose.router.stack/ChildStack.<init>|<init>(com.arkivanov.decompose.Child.Created<1:0,1:1>;kotlin.collections.List<com.arkivanov.decompose.Child.Created<1:0,1:1>>){}[0]
final fun component1(): com.arkivanov.decompose/Child.Created<#A, #B> // com.arkivanov.decompose.router.stack/ChildStack.component1|component1(){}[0]
final fun component2(): kotlin.collections/List<com.arkivanov.decompose/Child.Created<#A, #B>> // com.arkivanov.decompose.router.stack/ChildStack.component2|component2(){}[0]
Expand Down Expand Up @@ -233,6 +234,11 @@ final inline fun <#A: kotlin/Any> (com.arkivanov.decompose.router.stack/StackNav
final inline fun <#A: kotlin/Any> (com.arkivanov.decompose.router.stack/StackNavigator<#A>).com.arkivanov.decompose.router.stack/pushToFront(#A, crossinline kotlin/Function0<kotlin/Unit> = ...) // com.arkivanov.decompose.router.stack/pushToFront|[email protected]<0:0>(0:0;kotlin.Function0<kotlin.Unit>){0§<kotlin.Any>}[0]
final inline fun <#A: kotlin/Any> (com.arkivanov.decompose.router.stack/StackNavigator<#A>).com.arkivanov.decompose.router.stack/replaceAll(kotlin/Array<out #A>..., crossinline kotlin/Function0<kotlin/Unit> = ...) // com.arkivanov.decompose.router.stack/replaceAll|[email protected]<0:0>(kotlin.Array<out|0:0>...;kotlin.Function0<kotlin.Unit>){0§<kotlin.Any>}[0]
final inline fun <#A: kotlin/Any> (com.arkivanov.decompose.router.stack/StackNavigator<#A>).com.arkivanov.decompose.router.stack/replaceCurrent(#A, crossinline kotlin/Function0<kotlin/Unit> = ...) // com.arkivanov.decompose.router.stack/replaceCurrent|replaceCurrent@com.arkivanov.decompose.router.stack.StackNavigator<0:0>(0:0;kotlin.Function0<kotlin.Unit>){0§<kotlin.Any>}[0]
final object com.arkivanov.decompose/DecomposeExperimentFlags { // com.arkivanov.decompose/DecomposeExperimentFlags|null[0]
final var duplicateConfigurationsEnabled // com.arkivanov.decompose/DecomposeExperimentFlags.duplicateConfigurationsEnabled|{}duplicateConfigurationsEnabled[0]
final fun <get-duplicateConfigurationsEnabled>(): kotlin/Boolean // com.arkivanov.decompose/DecomposeExperimentFlags.duplicateConfigurationsEnabled.<get-duplicateConfigurationsEnabled>|<get-duplicateConfigurationsEnabled>(){}[0]
final fun <set-duplicateConfigurationsEnabled>(kotlin/Boolean) // com.arkivanov.decompose/DecomposeExperimentFlags.duplicateConfigurationsEnabled.<set-duplicateConfigurationsEnabled>|<set-duplicateConfigurationsEnabled>(kotlin.Boolean){}[0]
}
final val com.arkivanov.decompose.router.slot/child // com.arkivanov.decompose.router.slot/child|@com.arkivanov.decompose.value.Value<com.arkivanov.decompose.router.slot.ChildSlot<0:0,0:1>>{0§<kotlin.Any>;1§<kotlin.Any>}child[0]
final fun <#A1: kotlin/Any, #B1: kotlin/Any> (com.arkivanov.decompose.value/Value<com.arkivanov.decompose.router.slot/ChildSlot<#A1, #B1>>).<get-child>(): com.arkivanov.decompose/Child.Created<#A1, #B1>? // com.arkivanov.decompose.router.slot/child.<get-child>|<get-child>@com.arkivanov.decompose.value.Value<com.arkivanov.decompose.router.slot.ChildSlot<0:0,0:1>>(){0§<kotlin.Any>;1§<kotlin.Any>}[0]
final val com.arkivanov.decompose.router.stack/active // com.arkivanov.decompose.router.stack/active|@com.arkivanov.decompose.value.Value<com.arkivanov.decompose.router.stack.ChildStack<0:0,0:1>>{0§<kotlin.Any>;1§<kotlin.Any>}active[0]
Expand All @@ -258,31 +264,43 @@ sealed class <#A: out kotlin/Any, #B: out kotlin/Any> com.arkivanov.decompose/Ch
abstract fun <get-configuration>(): #A // com.arkivanov.decompose/Child.configuration.<get-configuration>|<get-configuration>(){}[0]
abstract val instance // com.arkivanov.decompose/Child.instance|{}instance[0]
abstract fun <get-instance>(): #B? // com.arkivanov.decompose/Child.instance.<get-instance>|<get-instance>(){}[0]
abstract val key // com.arkivanov.decompose/Child.key|{}key[0]
abstract fun <get-key>(): kotlin/Any // com.arkivanov.decompose/Child.key.<get-key>|<get-key>(){}[0]
constructor <init>() // com.arkivanov.decompose/Child.<init>|<init>(){}[0]
final class <#A1: out kotlin/Any, #B1: out kotlin/Any> Created : com.arkivanov.decompose/Child<#A1, #B1> { // com.arkivanov.decompose/Child.Created|null[0]
constructor <init>(#A1, #B1) // com.arkivanov.decompose/Child.Created.<init>|<init>(1:0;1:1){}[0]
constructor <init>(#A1, #B1, kotlin/Any) // com.arkivanov.decompose/Child.Created.<init>|<init>(1:0;1:1;kotlin.Any){}[0]
final fun component1(): #A1 // com.arkivanov.decompose/Child.Created.component1|component1(){}[0]
final fun component2(): #B1 // com.arkivanov.decompose/Child.Created.component2|component2(){}[0]
final fun copy(#A1 = ..., #B1 = ...): com.arkivanov.decompose/Child.Created<#A1, #B1> // com.arkivanov.decompose/Child.Created.copy|copy(1:0;1:1){}[0]
final fun component3(): kotlin/Any // com.arkivanov.decompose/Child.Created.component3|component3(){}[0]
final fun copy(#A1 = ..., #B1 = ..., kotlin/Any = ...): com.arkivanov.decompose/Child.Created<#A1, #B1> // com.arkivanov.decompose/Child.Created.copy|copy(1:0;1:1;kotlin.Any){}[0]
final fun copy(#A1, #B1): com.arkivanov.decompose/Child<#A1, #B1> // com.arkivanov.decompose/Child.Created.copy|copy(1:0;1:1){}[0]
final fun equals(kotlin/Any?): kotlin/Boolean // com.arkivanov.decompose/Child.Created.equals|equals(kotlin.Any?){}[0]
final fun hashCode(): kotlin/Int // com.arkivanov.decompose/Child.Created.hashCode|hashCode(){}[0]
final fun toString(): kotlin/String // com.arkivanov.decompose/Child.Created.toString|toString(){}[0]
final val configuration // com.arkivanov.decompose/Child.Created.configuration|{}configuration[0]
final fun <get-configuration>(): #A1 // com.arkivanov.decompose/Child.Created.configuration.<get-configuration>|<get-configuration>(){}[0]
final val instance // com.arkivanov.decompose/Child.Created.instance|{}instance[0]
final fun <get-instance>(): #B1 // com.arkivanov.decompose/Child.Created.instance.<get-instance>|<get-instance>(){}[0]
final val key // com.arkivanov.decompose/Child.Created.key|{}key[0]
final fun <get-key>(): kotlin/Any // com.arkivanov.decompose/Child.Created.key.<get-key>|<get-key>(){}[0]
}
final class <#A1: out kotlin/Any> Destroyed : com.arkivanov.decompose/Child<#A1, kotlin/Nothing> { // com.arkivanov.decompose/Child.Destroyed|null[0]
constructor <init>(#A1) // com.arkivanov.decompose/Child.Destroyed.<init>|<init>(1:0){}[0]
constructor <init>(#A1, kotlin/Any) // com.arkivanov.decompose/Child.Destroyed.<init>|<init>(1:0;kotlin.Any){}[0]
final fun component1(): #A1 // com.arkivanov.decompose/Child.Destroyed.component1|component1(){}[0]
final fun copy(#A1 = ...): com.arkivanov.decompose/Child.Destroyed<#A1> // com.arkivanov.decompose/Child.Destroyed.copy|copy(1:0){}[0]
final fun component2(): kotlin/Any // com.arkivanov.decompose/Child.Destroyed.component2|component2(){}[0]
final fun copy(#A1 = ..., kotlin/Any = ...): com.arkivanov.decompose/Child.Destroyed<#A1> // com.arkivanov.decompose/Child.Destroyed.copy|copy(1:0;kotlin.Any){}[0]
final fun copy(#A1): com.arkivanov.decompose/Child<#A1, kotlin/Nothing> // com.arkivanov.decompose/Child.Destroyed.copy|copy(1:0){}[0]
final fun equals(kotlin/Any?): kotlin/Boolean // com.arkivanov.decompose/Child.Destroyed.equals|equals(kotlin.Any?){}[0]
final fun hashCode(): kotlin/Int // com.arkivanov.decompose/Child.Destroyed.hashCode|hashCode(){}[0]
final fun toString(): kotlin/String // com.arkivanov.decompose/Child.Destroyed.toString|toString(){}[0]
final val configuration // com.arkivanov.decompose/Child.Destroyed.configuration|{}configuration[0]
final fun <get-configuration>(): #A1 // com.arkivanov.decompose/Child.Destroyed.configuration.<get-configuration>|<get-configuration>(){}[0]
final val instance // com.arkivanov.decompose/Child.Destroyed.instance|{}instance[0]
final fun <get-instance>(): kotlin/Nothing? // com.arkivanov.decompose/Child.Destroyed.instance.<get-instance>|<get-instance>(){}[0]
final val key // com.arkivanov.decompose/Child.Destroyed.key|{}key[0]
final fun <get-key>(): kotlin/Any // com.arkivanov.decompose/Child.Destroyed.key.<get-key>|<get-key>(){}[0]
}
}
// Targets: [js, wasmJs]
Expand Down
24 changes: 20 additions & 4 deletions decompose/api/jvm/decompose.api
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,39 @@ public abstract interface class com/arkivanov/decompose/Cancellation {
public abstract class com/arkivanov/decompose/Child {
public abstract fun getConfiguration ()Ljava/lang/Object;
public abstract fun getInstance ()Ljava/lang/Object;
public abstract fun getKey ()Ljava/lang/Object;
}

public final class com/arkivanov/decompose/Child$Created : com/arkivanov/decompose/Child {
public fun <init> (Ljava/lang/Object;Ljava/lang/Object;)V
public fun <init> (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V
public final fun component1 ()Ljava/lang/Object;
public final fun component2 ()Ljava/lang/Object;
public final fun copy (Ljava/lang/Object;Ljava/lang/Object;)Lcom/arkivanov/decompose/Child$Created;
public static synthetic fun copy$default (Lcom/arkivanov/decompose/Child$Created;Ljava/lang/Object;Ljava/lang/Object;ILjava/lang/Object;)Lcom/arkivanov/decompose/Child$Created;
public final fun component3 ()Ljava/lang/Object;
public final synthetic fun copy (Ljava/lang/Object;Ljava/lang/Object;)Lcom/arkivanov/decompose/Child;
public final fun copy (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Lcom/arkivanov/decompose/Child$Created;
public static synthetic fun copy$default (Lcom/arkivanov/decompose/Child$Created;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;ILjava/lang/Object;)Lcom/arkivanov/decompose/Child$Created;
public fun equals (Ljava/lang/Object;)Z
public fun getConfiguration ()Ljava/lang/Object;
public fun getInstance ()Ljava/lang/Object;
public fun getKey ()Ljava/lang/Object;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class com/arkivanov/decompose/Child$Destroyed : com/arkivanov/decompose/Child {
public fun <init> (Ljava/lang/Object;)V
public fun <init> (Ljava/lang/Object;Ljava/lang/Object;)V
public final fun component1 ()Ljava/lang/Object;
public final fun copy (Ljava/lang/Object;)Lcom/arkivanov/decompose/Child$Destroyed;
public static synthetic fun copy$default (Lcom/arkivanov/decompose/Child$Destroyed;Ljava/lang/Object;ILjava/lang/Object;)Lcom/arkivanov/decompose/Child$Destroyed;
public final fun component2 ()Ljava/lang/Object;
public final synthetic fun copy (Ljava/lang/Object;)Lcom/arkivanov/decompose/Child;
public final fun copy (Ljava/lang/Object;Ljava/lang/Object;)Lcom/arkivanov/decompose/Child$Destroyed;
public static synthetic fun copy$default (Lcom/arkivanov/decompose/Child$Destroyed;Ljava/lang/Object;Ljava/lang/Object;ILjava/lang/Object;)Lcom/arkivanov/decompose/Child$Destroyed;
public fun equals (Ljava/lang/Object;)Z
public fun getConfiguration ()Ljava/lang/Object;
public synthetic fun getInstance ()Ljava/lang/Object;
public fun getInstance ()Ljava/lang/Void;
public fun getKey ()Ljava/lang/Object;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}
Expand All @@ -49,6 +58,12 @@ public abstract interface class com/arkivanov/decompose/ComponentContextFactoryO
public abstract fun getComponentContextFactory ()Lcom/arkivanov/decompose/ComponentContextFactory;
}

public final class com/arkivanov/decompose/DecomposeExperimentFlags {
public static final field INSTANCE Lcom/arkivanov/decompose/DecomposeExperimentFlags;
public final fun getDuplicateConfigurationsEnabled ()Z
public final fun setDuplicateConfigurationsEnabled (Z)V
}

public final class com/arkivanov/decompose/DefaultComponentContext : com/arkivanov/decompose/ComponentContext {
public fun <init> (Lcom/arkivanov/essenty/lifecycle/Lifecycle;)V
public fun <init> (Lcom/arkivanov/essenty/lifecycle/Lifecycle;Lcom/arkivanov/essenty/statekeeper/StateKeeper;Lcom/arkivanov/essenty/instancekeeper/InstanceKeeper;Lcom/arkivanov/essenty/backhandler/BackHandler;)V
Expand Down Expand Up @@ -250,6 +265,7 @@ public final class com/arkivanov/decompose/router/stack/ChildStack {
public fun <init> (Lcom/arkivanov/decompose/Child$Created;Ljava/util/List;)V
public synthetic fun <init> (Lcom/arkivanov/decompose/Child$Created;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Ljava/lang/Object;Ljava/lang/Object;)V
public fun <init> (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V
public final fun component1 ()Lcom/arkivanov/decompose/Child$Created;
public final fun component2 ()Ljava/util/List;
public final fun copy (Lcom/arkivanov/decompose/Child$Created;Ljava/util/List;)Lcom/arkivanov/decompose/router/stack/ChildStack;
Expand Down
34 changes: 31 additions & 3 deletions decompose/src/commonMain/kotlin/com/arkivanov/decompose/Child.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,42 @@ sealed class Child<out C : Any, out T : Any> {
abstract val configuration: C
abstract val instance: T?

data class Created<out C : Any, out T : Any>(
@ExperimentalDecomposeApi
abstract val key: Any

data class Created<out C : Any, out T : Any> @ExperimentalDecomposeApi constructor(
override val configuration: C,
override val instance: T,
) : Child<C, T>()

data class Destroyed<out C : Any>(
@property:ExperimentalDecomposeApi
override val key: Any,
) : Child<C, T>() {
constructor(configuration: C, instance: T) : this(
configuration = configuration,
instance = instance,
key = configuration,
)

@Deprecated(message = "For binary compatibility", level = DeprecationLevel.HIDDEN)
fun copy(configuration: @UnsafeVariance C, instance: @UnsafeVariance T): Child<C, T> =
copy(configuration = configuration, instance = instance)
}

data class Destroyed<out C : Any> @ExperimentalDecomposeApi constructor(
override val configuration: C,

@property:ExperimentalDecomposeApi
override val key: Any,
) : Child<C, Nothing>() {
constructor(configuration: C) : this(
configuration = configuration,
key = configuration,
)

override val instance: Nothing? = null

@Deprecated(message = "For binary compatibility", level = DeprecationLevel.HIDDEN)
fun copy(configuration: @UnsafeVariance C): Child<C, Nothing> =
copy(configuration = configuration)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.arkivanov.decompose

@ExperimentalDecomposeApi
object DecomposeExperimentFlags {

var duplicateConfigurationsEnabled: Boolean = false
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@ internal class GettingList<out T>(
override fun get(index: Int): T =
get.invoke(index)
}

internal inline fun <T, R> List<T>.mapped(crossinline mapper: (T) -> R): List<R> =
GettingList(size = size) { mapper(get(it)) }
Loading

0 comments on commit ce4d007

Please sign in to comment.