diff --git a/trikot-foundation/trikotFoundation/api/android/trikotFoundation.api b/trikot-foundation/trikotFoundation/api/android/trikotFoundation.api index 659d0b07e..e2f4d48e5 100644 --- a/trikot-foundation/trikotFoundation/api/android/trikotFoundation.api +++ b/trikot-foundation/trikotFoundation/api/android/trikotFoundation.api @@ -203,6 +203,7 @@ public final class com/mirego/trikot/foundation/concurrent/AtomicReference { public fun (Ljava/lang/Object;)V public final fun compareAndSet (Ljava/lang/Object;Ljava/lang/Object;)Z public final fun compareAndSwap (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; + public final fun getAndSet (Ljava/lang/Object;)Ljava/lang/Object; public final fun getValue ()Ljava/lang/Object; public final fun setOrThrow (Ljava/lang/Object;Ljava/lang/Object;)V public final fun setOrThrow (Ljava/lang/Object;Ljava/lang/Object;Lkotlin/jvm/functions/Function0;)V diff --git a/trikot-foundation/trikotFoundation/api/jvm/trikotFoundation.api b/trikot-foundation/trikotFoundation/api/jvm/trikotFoundation.api index 659d0b07e..e2f4d48e5 100644 --- a/trikot-foundation/trikotFoundation/api/jvm/trikotFoundation.api +++ b/trikot-foundation/trikotFoundation/api/jvm/trikotFoundation.api @@ -203,6 +203,7 @@ public final class com/mirego/trikot/foundation/concurrent/AtomicReference { public fun (Ljava/lang/Object;)V public final fun compareAndSet (Ljava/lang/Object;Ljava/lang/Object;)Z public final fun compareAndSwap (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; + public final fun getAndSet (Ljava/lang/Object;)Ljava/lang/Object; public final fun getValue ()Ljava/lang/Object; public final fun setOrThrow (Ljava/lang/Object;Ljava/lang/Object;)V public final fun setOrThrow (Ljava/lang/Object;Ljava/lang/Object;Lkotlin/jvm/functions/Function0;)V diff --git a/trikot-foundation/trikotFoundation/src/commonMain/kotlin/com/mirego/trikot/foundation/concurrent/AtomicReference.kt b/trikot-foundation/trikotFoundation/src/commonMain/kotlin/com/mirego/trikot/foundation/concurrent/AtomicReference.kt index 8ceee6c0b..56a69a945 100644 --- a/trikot-foundation/trikotFoundation/src/commonMain/kotlin/com/mirego/trikot/foundation/concurrent/AtomicReference.kt +++ b/trikot-foundation/trikotFoundation/src/commonMain/kotlin/com/mirego/trikot/foundation/concurrent/AtomicReference.kt @@ -23,6 +23,10 @@ class AtomicReference(value: T) { fun compareAndSwap(expected: T, new: T): T { return if (compareAndSet(expected, new)) new else value } + + fun getAndSet(new: T): T { + return atomicValue.getAndSet(new) + } } fun AtomicReference.setOrThrow(new: T) = setOrThrow(value, new) diff --git a/trikot-streams/streams/src/commonMain/kotlin/com/mirego/trikot/streams/cancellable/CancellableManagerProvider.kt b/trikot-streams/streams/src/commonMain/kotlin/com/mirego/trikot/streams/cancellable/CancellableManagerProvider.kt index e1e27ccde..ae521ef4e 100644 --- a/trikot-streams/streams/src/commonMain/kotlin/com/mirego/trikot/streams/cancellable/CancellableManagerProvider.kt +++ b/trikot-streams/streams/src/commonMain/kotlin/com/mirego/trikot/streams/cancellable/CancellableManagerProvider.kt @@ -1,20 +1,29 @@ package com.mirego.trikot.streams.cancellable import com.mirego.trikot.foundation.concurrent.AtomicReference +import com.mirego.trikot.foundation.concurrent.dispatchQueue.SynchronousSerialQueue class CancellableManagerProvider : Cancellable { - private val cancellableManager = CancellableManager() + private val serialQueue = SynchronousSerialQueue() private val internalCancellableManagerRef = AtomicReference(CancellableManager()) + private val isCancelled = AtomicReference(false) fun cancelPreviousAndCreate(): CancellableManager { - internalCancellableManagerRef.value.cancel() - return CancellableManager().also { - internalCancellableManagerRef.setOrThrow(internalCancellableManagerRef.value, it) - cancellableManager.add(it) + return CancellableManager().also { cancellableManager -> + internalCancellableManagerRef.getAndSet(cancellableManager).cancel() + serialQueue.dispatch { + if (isCancelled.value) { + cancellableManager.cancel() + } + } } } override fun cancel() { - cancellableManager.cancel() + serialQueue.dispatch { + if (isCancelled.compareAndSet(isCancelled.value, true)) { + internalCancellableManagerRef.value.cancel() + } + } } } diff --git a/trikot-streams/streams/src/commonTest/kotlin/com/mirego/trikot/streams/cancellable/CancellableManagerProviderTests.kt b/trikot-streams/streams/src/commonTest/kotlin/com/mirego/trikot/streams/cancellable/CancellableManagerProviderTests.kt index 21a9a21ee..090d0020a 100644 --- a/trikot-streams/streams/src/commonTest/kotlin/com/mirego/trikot/streams/cancellable/CancellableManagerProviderTests.kt +++ b/trikot-streams/streams/src/commonTest/kotlin/com/mirego/trikot/streams/cancellable/CancellableManagerProviderTests.kt @@ -24,4 +24,15 @@ class CancellableManagerProviderTests { assertTrue { cancelled } } + + @Test + fun requestingACancellableManagerFromACancelledProviderReturnsACancelledCancellableManager() { + val cancellableManagerProvider = CancellableManagerProvider() + cancellableManagerProvider.cancel() + val cancellableManager = cancellableManagerProvider.cancelPreviousAndCreate() + var cancelled = false + cancellableManager.add { cancelled = true } + + assertTrue { cancelled } + } }