Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Removed deprecated Value#subscribe and Value#unsubscribe methods #554

Merged
merged 1 commit into from
Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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