-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #36 from respawn-app/2.2.2-rc
2.2.2-rc
- Loading branch information
Showing
22 changed files
with
238 additions
and
173 deletions.
There are no files selected for viewing
2 changes: 2 additions & 0 deletions
2
android-compose/src/main/kotlin/pro/respawn/flowmvi/android/compose/preview/EmptyReceiver.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
36 changes: 0 additions & 36 deletions
36
core/src/commonMain/kotlin/pro/respawn/flowmvi/api/Recoverable.kt
This file was deleted.
Oops, something went wrong.
12 changes: 12 additions & 0 deletions
12
core/src/commonMain/kotlin/pro/respawn/flowmvi/api/UnrecoverableException.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package pro.respawn.flowmvi.api | ||
|
||
/** | ||
* An exception that has happened in the [Store] that cannot be recovered from. | ||
* This is either an exception resulting from developer errors (such as unhandled intents), | ||
* or an exception while trying to recover from another exception (which is prohibited). | ||
* You may also use this to bypass store plugins handling this particular exception. | ||
*/ | ||
public class UnrecoverableException( | ||
override val cause: Exception? = null, | ||
override val message: String? = null, | ||
) : IllegalStateException(message, cause) |
41 changes: 41 additions & 0 deletions
41
core/src/commonMain/kotlin/pro/respawn/flowmvi/exceptions/StoreExceptions.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
@file:Suppress("FunctionName") | ||
|
||
package pro.respawn.flowmvi.exceptions | ||
|
||
import pro.respawn.flowmvi.api.UnrecoverableException | ||
|
||
internal fun NonSuspendingSubscriberException() = UnrecoverableException( | ||
message = """ | ||
You have subscribed to the store, but your subscribe() block has returned early (without throwing a | ||
CancellationException). When you subscribe, make sure to continue collecting values from the store until the Job | ||
Returned from the subscribe() is cancelled as you likely don't want to stop being subscribed to the store | ||
(i.e. complete the subscription job on your own). | ||
""" | ||
.trimIndent(), | ||
cause = null, | ||
) | ||
|
||
internal fun UnhandledIntentException() = UnrecoverableException( | ||
message = """ | ||
An intent has not been handled after calling all plugins. | ||
You likely don't want this to happen because intents are supposed to be acted upon. | ||
Make sure you have at least one plugin that handles intents, such as reducePlugin(). | ||
""" | ||
.trimIndent(), | ||
cause = null, | ||
) | ||
|
||
internal fun RecursiveRecoverException(cause: Exception) = UnrecoverableException( | ||
message = """ | ||
Recursive recover detected, which means you have thrown in a recover plugin or in the `onException` block. | ||
Please never throw while recovering from exceptions, or that will result in an infinite loop. | ||
""".trimIndent(), | ||
cause = cause | ||
) | ||
|
||
internal fun UnhandledStoreException(cause: Exception) = UnrecoverableException( | ||
message = """ | ||
Store has run all its plugins (exception handlers) but the exception was not handled by any of them. | ||
""".trimIndent(), | ||
cause = cause, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
72 changes: 72 additions & 0 deletions
72
core/src/commonMain/kotlin/pro/respawn/flowmvi/modules/RecoverModule.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package pro.respawn.flowmvi.modules | ||
|
||
import kotlinx.coroutines.CoroutineExceptionHandler | ||
import kotlinx.coroutines.launch | ||
import kotlinx.coroutines.withContext | ||
import pro.respawn.flowmvi.api.MVIAction | ||
import pro.respawn.flowmvi.api.MVIIntent | ||
import pro.respawn.flowmvi.api.MVIState | ||
import pro.respawn.flowmvi.api.PipelineContext | ||
import pro.respawn.flowmvi.api.Store | ||
import pro.respawn.flowmvi.api.UnrecoverableException | ||
import pro.respawn.flowmvi.exceptions.RecursiveRecoverException | ||
import kotlin.coroutines.CoroutineContext | ||
import kotlin.coroutines.cancellation.CancellationException | ||
import kotlin.coroutines.coroutineContext | ||
|
||
/** | ||
* An entity that can [recover] from exceptions happening during its lifecycle. Most often, a [Store] | ||
*/ | ||
@Suppress("FUN_INTERFACE_WITH_SUSPEND_FUNCTION") // https://youtrack.jetbrains.com/issue/KTIJ-7642 | ||
internal fun interface RecoverModule<S : MVIState, I : MVIIntent, A : MVIAction> : CoroutineContext.Element { | ||
|
||
override val key: CoroutineContext.Key<*> get() = RecoverModule | ||
|
||
/** | ||
* Recover from an exception in the given context. | ||
*/ | ||
suspend fun PipelineContext<S, I, A>.recover(e: Exception) | ||
|
||
/** | ||
* Run [block] catching any exceptions and invoking [recover]. This will add this [RecoverModule] key to the coroutine | ||
* context of the [recover] block. | ||
*/ | ||
suspend fun PipelineContext<S, I, A>.catch(block: suspend () -> Unit): Unit = try { | ||
withContext(this@RecoverModule) { block() } | ||
} catch (expected: Exception) { | ||
when { | ||
expected is CancellationException || expected is UnrecoverableException -> throw expected | ||
alreadyRecovered() -> throw RecursiveRecoverException(expected) | ||
else -> recover(expected) | ||
} | ||
} | ||
|
||
@Suppress("FunctionName") | ||
fun PipelineContext<S, I, A>.PipelineExceptionHandler() = CoroutineExceptionHandler { ctx, e -> | ||
when { | ||
e !is Exception || e is CancellationException -> throw e | ||
e is UnrecoverableException -> throw e.unwrapRecursion() | ||
ctx.alreadyRecovered -> throw e | ||
// add Recoverable to the coroutine context | ||
// and handle the exception asynchronously to allow suspending inside recover | ||
// Do NOT use the "ctx" parameter here, as that coroutine context is already invalid and will not launch | ||
else -> launch(this@RecoverModule) { recover(e) }.invokeOnCompletion { cause -> | ||
if (cause != null && cause !is CancellationException) throw cause | ||
} | ||
} | ||
} | ||
|
||
companion object : CoroutineContext.Key<RecoverModule<*, *, *>> | ||
} | ||
|
||
private tailrec fun UnrecoverableException.unwrapRecursion(): Exception = when (val cause = cause) { | ||
null -> this | ||
this -> this // cause is the same exception | ||
is UnrecoverableException -> cause.unwrapRecursion() | ||
is CancellationException -> throw cause | ||
else -> cause | ||
} | ||
|
||
internal suspend fun alreadyRecovered() = coroutineContext.alreadyRecovered | ||
|
||
private val CoroutineContext.alreadyRecovered get() = this[RecoverModule] != null |
24 changes: 0 additions & 24 deletions
24
core/src/commonMain/kotlin/pro/respawn/flowmvi/modules/Recoverable.kt
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.