Skip to content

Commit

Permalink
Removed deprecated Value#subscribe and Value#unsubscribe methods, ren…
Browse files Browse the repository at this point in the history
…amed Value#observe to Value#subscribe
  • Loading branch information
arkivanov committed Dec 5, 2023
1 parent 6ef4c7a commit a559bad
Show file tree
Hide file tree
Showing 18 changed files with 66 additions and 137 deletions.
8 changes: 3 additions & 5 deletions decompose/api/android/decompose.api
Original file line number Diff line number Diff line change
Expand Up @@ -364,15 +364,13 @@ public final class com/arkivanov/decompose/value/ObserveLifecycleMode : java/lan
public abstract class com/arkivanov/decompose/value/Value {
public fun <init> ()V
public abstract fun getValue ()Ljava/lang/Object;
public final fun observe (Lkotlin/jvm/functions/Function1;)Lcom/arkivanov/decompose/Cancellation;
public abstract fun subscribe (Lkotlin/jvm/functions/Function1;)V
public abstract fun unsubscribe (Lkotlin/jvm/functions/Function1;)V
public abstract fun subscribe (Lkotlin/jvm/functions/Function1;)Lcom/arkivanov/decompose/Cancellation;
}

public final class com/arkivanov/decompose/value/ValueExtKt {
public static final fun getValue (Lcom/arkivanov/decompose/value/Value;Ljava/lang/Object;Lkotlin/reflect/KProperty;)Ljava/lang/Object;
public static final fun observe (Lcom/arkivanov/decompose/value/Value;Lcom/arkivanov/essenty/lifecycle/Lifecycle;Lcom/arkivanov/decompose/value/ObserveLifecycleMode;Lkotlin/jvm/functions/Function1;)V
public static synthetic fun observe$default (Lcom/arkivanov/decompose/value/Value;Lcom/arkivanov/essenty/lifecycle/Lifecycle;Lcom/arkivanov/decompose/value/ObserveLifecycleMode;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public static final fun subscribe (Lcom/arkivanov/decompose/value/Value;Lcom/arkivanov/essenty/lifecycle/Lifecycle;Lcom/arkivanov/decompose/value/ObserveLifecycleMode;Lkotlin/jvm/functions/Function1;)V
public static synthetic fun subscribe$default (Lcom/arkivanov/decompose/value/Value;Lcom/arkivanov/essenty/lifecycle/Lifecycle;Lcom/arkivanov/decompose/value/ObserveLifecycleMode;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
}

public final class com/arkivanov/decompose/value/operator/MapKt {
Expand Down
8 changes: 3 additions & 5 deletions decompose/api/jvm/decompose.api
Original file line number Diff line number Diff line change
Expand Up @@ -350,15 +350,13 @@ public final class com/arkivanov/decompose/value/ObserveLifecycleMode : java/lan
public abstract class com/arkivanov/decompose/value/Value {
public fun <init> ()V
public abstract fun getValue ()Ljava/lang/Object;
public final fun observe (Lkotlin/jvm/functions/Function1;)Lcom/arkivanov/decompose/Cancellation;
public abstract fun subscribe (Lkotlin/jvm/functions/Function1;)V
public abstract fun unsubscribe (Lkotlin/jvm/functions/Function1;)V
public abstract fun subscribe (Lkotlin/jvm/functions/Function1;)Lcom/arkivanov/decompose/Cancellation;
}

public final class com/arkivanov/decompose/value/ValueExtKt {
public static final fun getValue (Lcom/arkivanov/decompose/value/Value;Ljava/lang/Object;Lkotlin/reflect/KProperty;)Ljava/lang/Object;
public static final fun observe (Lcom/arkivanov/decompose/value/Value;Lcom/arkivanov/essenty/lifecycle/Lifecycle;Lcom/arkivanov/decompose/value/ObserveLifecycleMode;Lkotlin/jvm/functions/Function1;)V
public static synthetic fun observe$default (Lcom/arkivanov/decompose/value/Value;Lcom/arkivanov/essenty/lifecycle/Lifecycle;Lcom/arkivanov/decompose/value/ObserveLifecycleMode;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public static final fun subscribe (Lcom/arkivanov/decompose/value/Value;Lcom/arkivanov/essenty/lifecycle/Lifecycle;Lcom/arkivanov/decompose/value/ObserveLifecycleMode;Lkotlin/jvm/functions/Function1;)V
public static synthetic fun subscribe$default (Lcom/arkivanov/decompose/value/Value;Lcom/arkivanov/essenty/lifecycle/Lifecycle;Lcom/arkivanov/decompose/value/ObserveLifecycleMode;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
}

public final class com/arkivanov/decompose/value/operator/MapKt {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package com.arkivanov.decompose.value

import com.arkivanov.decompose.Cancellation
import com.arkivanov.decompose.Lock
import com.arkivanov.decompose.synchronized

/**
* Returns a new instance of [MutableValue] initialized with the provided [initialValue].
*/
@Suppress("FunctionName") // Factory function
fun <T : Any> MutableValue(initialValue: T): MutableValue<T> = MutableValueImpl(initialValue)

private class MutableValueImpl<T : Any>(initialValue: T) : MutableValue<T>() {
Expand Down Expand Up @@ -70,13 +70,13 @@ private class MutableValueImpl<T : Any>(initialValue: T) : MutableValue<T>() {
}
}

@Deprecated(
"Calling this method from Swift leaks the observer, " +
"because Kotlin wraps the function passed from Swift every time the method is called. " +
"Please use the new `observe` method which returns `Disposable`.",
level = DeprecationLevel.WARNING,
)
override fun subscribe(observer: (T) -> Unit) {
override fun subscribe(observer: (T) -> Unit): Cancellation {
subscribeObserver(observer)

return Cancellation { unsubscribeObserver(observer) }
}

private fun subscribeObserver(observer: (T) -> Unit) {
lock.synchronized {
if (observer in observers) {
return
Expand All @@ -103,13 +103,7 @@ private class MutableValueImpl<T : Any>(initialValue: T) : MutableValue<T>() {
}
}

@Deprecated(
"Calling this method from Swift doesn't have any effect, " +
"because Kotlin wraps the function passed from Swift every time the method is called. " +
"Please use the new `observe` method which returns `Disposable`.",
level = DeprecationLevel.WARNING,
)
override fun unsubscribe(observer: (T) -> Unit) {
private fun unsubscribeObserver(observer: (T) -> Unit) {
lock.synchronized { observers -= observer }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,39 +14,10 @@ abstract class Value<out T : Any> {
*/
abstract val value: T

/**
* Subscribes the provided [observer] for value updates. The current value is emitted synchronously on subscription.
*/
@Deprecated(
message = "Calling this method from Swift leaks the observer, " +
"because Kotlin wraps the function passed from Swift every time the method is called. " +
"Please use the new `observe` method which returns `Disposable`.",
level = DeprecationLevel.WARNING,
)
abstract fun subscribe(observer: (T) -> Unit)

/**
* Unsubscribes the provided [observer] from value updates.
*/
@Deprecated(
message = "Calling this method from Swift doesn't have any effect, " +
"because Kotlin wraps the function passed from Swift every time the method is called. " +
"Please use the new `observe` method which returns `Disposable`.",
level = DeprecationLevel.WARNING,
)
abstract fun unsubscribe(observer: (T) -> Unit)

/**
* Subscribes the provided [observer] for value updates. The current value is emitted synchronously on subscription.
*
* Note: most likely this method will be renamed to `subscribe` in the next major release, once deprecated methods are removed.
*
* @return [Cancellation] token to cancel the subscription.
*/
@Suppress("DEPRECATION")
fun observe(observer: (T) -> Unit): Cancellation {
subscribe(observer)

return Cancellation { unsubscribe(observer) }
}
abstract fun subscribe(observer: (T) -> Unit): Cancellation
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import kotlin.reflect.KProperty

operator fun <T : Any> Value<T>.getValue(thisRef: Any?, property: KProperty<*>): T = value

fun <T : Any> Value<T>.observe(
fun <T : Any> Value<T>.subscribe(
lifecycle: Lifecycle,
mode: ObserveLifecycleMode = ObserveLifecycleMode.START_STOP,
observer: (T) -> Unit,
Expand All @@ -17,19 +17,19 @@ fun <T : Any> Value<T>.observe(
when (mode) {
ObserveLifecycleMode.CREATE_DESTROY ->
lifecycle.subscribe(
onCreate = { cancellation = observe(observer) },
onCreate = { cancellation = subscribe(observer) },
onDestroy = { cancellation?.cancel() },
)

ObserveLifecycleMode.START_STOP ->
lifecycle.subscribe(
onStart = { cancellation = observe(observer) },
onStart = { cancellation = subscribe(observer) },
onStop = { cancellation?.cancel() },
)

ObserveLifecycleMode.RESUME_PAUSE ->
lifecycle.subscribe(
onResume = { cancellation = observe(observer) },
onResume = { cancellation = subscribe(observer) },
onPause = { cancellation?.cancel() },
)
}.let {}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.arkivanov.decompose.value.operator

import com.arkivanov.decompose.Cancellation
import com.arkivanov.decompose.Lock
import com.arkivanov.decompose.synchronized
import com.arkivanov.decompose.value.Value
Expand All @@ -14,7 +15,6 @@ private class MappedValue<T : Any, out R : Any>(
private val lock = Lock()
private var lastUpstreamValue: T = upstream.value
private var lastMappedValue: R = mapper(lastUpstreamValue)
private var observers = HashMap<(R) -> Unit, (T) -> Unit>()

override val value: R get() = mapCached(upstream.value)

Expand All @@ -28,37 +28,6 @@ private class MappedValue<T : Any, out R : Any>(
lastMappedValue
}

@Deprecated(
"Calling this method from Swift leaks the observer, " +
"because Kotlin wraps the function passed from Swift every time the method is called. " +
"Please use the new `observe` method which returns `Disposable`.",
level = DeprecationLevel.WARNING,
)
override fun subscribe(observer: (R) -> Unit) {
val upstreamObserver: (T) -> Unit = { value -> observer(mapCached(value)) }

lock.synchronized {
if (observer in observers) {
return
}

observers[observer] = upstreamObserver
}

@Suppress("DEPRECATION")
upstream.subscribe(upstreamObserver)
}

@Deprecated(
"Calling this method from Swift doesn't have any effect, " +
"because Kotlin wraps the function passed from Swift every time the method is called. " +
"Please use the new `observe` method which returns `Disposable`.",
level = DeprecationLevel.WARNING,
)
override fun unsubscribe(observer: (R) -> Unit) {
val upstreamObserver = lock.synchronized { observers.remove(observer) } ?: return

@Suppress("DEPRECATION")
upstream.unsubscribe(upstreamObserver)
}
override fun subscribe(observer: (R) -> Unit): Cancellation =
upstream.subscribe { observer(mapCached(it)) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class MutableValueTest {
fun WHEN_subscribe_THEN_current_value_emitted() {
val values = ArrayList<Int>()

value.observe { values += it }
value.subscribe { values += it }

assertContentEquals(listOf(0), values)
}
Expand All @@ -37,7 +37,7 @@ class MutableValueTest {
val values = List(10) { ArrayList<Int>() }

repeat(10) { index ->
value.observe { values[index] += it }
value.subscribe { values[index] += it }
}

value.value = 1
Expand All @@ -50,7 +50,7 @@ class MutableValueTest {
@Test
fun GIVEN_unsubscribed_WHEN_value_changed_THEN_not_emitted() {
val values = ArrayList<Int>()
val cancellation = value.observe { values += it }
val cancellation = value.subscribe { values += it }
cancellation.cancel()
values.clear()

Expand All @@ -62,8 +62,8 @@ class MutableValueTest {
@Test
fun GIVEN_multiple_subscribes_and_one_unsubscribed_WHEN_value_changed_THEN_value_emitted_to_subscribed() {
val values = ArrayList<Int>()
val cancellation = value.observe {}
value.observe { values += it }
val cancellation = value.subscribe {}
value.subscribe { values += it }
cancellation.cancel()
values.clear()

Expand All @@ -75,8 +75,8 @@ class MutableValueTest {
@Test
fun GIVEN_multiple_subscribes_and_one_unsubscribed_WHEN_value_changed_THEN_value_not_emitted_to_unsubscribed() {
val values = ArrayList<Int>()
val cancellation = value.observe { values += it }
value.observe {}
val cancellation = value.subscribe { values += it }
value.subscribe {}
cancellation.cancel()
values.clear()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class ValueMapTest {

@Test
fun GIVEN_subscribed_WHEN_upstream_changed_THEN_value_mapped() {
mapped.observe {}
mapped.subscribe {}
upstream.value = "abcd"

val value = mapped.value
Expand All @@ -37,7 +37,7 @@ class ValueMapTest {
fun WHEN_subscribe_THEN_current_value_emitted() {
val values = ArrayList<Int>()

mapped.observe { values += it }
mapped.subscribe { values += it }

assertContentEquals(listOf(3), values)
}
Expand All @@ -47,7 +47,7 @@ class ValueMapTest {
val values = List(10) { ArrayList<Int>() }

repeat(10) { index ->
mapped.observe { values[index] += it }
mapped.subscribe { values[index] += it }
}

upstream.value = "abcd"
Expand All @@ -60,7 +60,7 @@ class ValueMapTest {
@Test
fun GIVEN_unsubscribed_WHEN_value_changed_THEN_not_emitted() {
val values = ArrayList<Int>()
val cancellation = mapped.observe { values += it }
val cancellation = mapped.subscribe { values += it }
cancellation.cancel()
values.clear()

Expand All @@ -72,8 +72,8 @@ class ValueMapTest {
@Test
fun GIVEN_multiple_subscribes_and_one_unsubscribed_WHEN_value_changed_THEN_value_emitted_to_subscribed() {
val values = ArrayList<Int>()
val cancellation = mapped.observe {}
mapped.observe { values += it }
val cancellation = mapped.subscribe {}
mapped.subscribe { values += it }
cancellation.cancel()
values.clear()

Expand All @@ -85,8 +85,8 @@ class ValueMapTest {
@Test
fun GIVEN_multiple_subscribes_and_one_unsubscribed_WHEN_value_changed_THEN_value_not_emitted_to_unsubscribed() {
val values = ArrayList<Int>()
val cancellation = mapped.observe { values += it }
mapped.observe {}
val cancellation = mapped.subscribe { values += it }
mapped.subscribe {}
cancellation.cancel()
values.clear()

Expand All @@ -106,9 +106,9 @@ class ValueMapTest {
it.length
}

mapped.observe {}
mapped.observe {}
mapped.observe {}
mapped.subscribe {}
mapped.subscribe {}
mapped.subscribe {}

assertEquals(1, count)
}
Expand All @@ -124,9 +124,9 @@ class ValueMapTest {
it.length
}

mapped.observe {}
mapped.observe {}
mapped.observe {}
mapped.subscribe {}
mapped.subscribe {}
mapped.subscribe {}
count = 0

upstream.value = "abcd"
Expand All @@ -145,11 +145,11 @@ class ValueMapTest {
it.length
}

mapped.observe {}
mapped.observe {}
mapped.subscribe {}
mapped.subscribe {}
upstream.value = "abcd"
count = 0
mapped.observe {}
mapped.subscribe {}


assertEquals(0, count)
Expand All @@ -166,8 +166,8 @@ class ValueMapTest {
it.length
}

mapped.observe {}
mapped.observe {}
mapped.subscribe {}
mapped.subscribe {}
upstream.value = "abcd"
count = 0
requireNotNull(upstream.value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ internal fun <T> List<T>.findFirstDifferentIndex(other: List<T>): Int {

internal fun <T : Any> Value<T>.subscribe(observer: (new: T, old: T) -> Unit) {
var old = value
observe { new ->
subscribe { new ->
val tmp = old
old = new
observer(new, tmp)
Expand Down
Loading

0 comments on commit a559bad

Please sign in to comment.