Add catchingExceptions method to replace runCatching (#4797)
- Add `runCatchingExceptions` and `mapCatchingExceptions` to replace `runCatching` and `mapCatching`.
- Make `tryOrNull { ... }` catch only exceptions too.
- Apply the changes to the whole project.
- Add new Rust fakes for tests to handle the code that's now unblocked - previously it just threw an `UnsatisfiedLinkError` which we ignored.
- Add a new `detekt-rules` project with a `RunCatchingRule` to prevent `runCatching` and `mapCatching` usages.
This commit is contained in:
committed by
GitHub
parent
01d6012760
commit
58a3ea8b1f
@@ -7,11 +7,20 @@
|
||||
|
||||
package io.element.android.libraries.core.data
|
||||
|
||||
inline fun <A> tryOrNull(onError: ((Throwable) -> Unit) = { }, operation: () -> A): A? {
|
||||
import kotlin.coroutines.cancellation.CancellationException
|
||||
|
||||
/**
|
||||
* Can be used to catch [Exception]s in a block of code, returning `null` if an exception occurs.
|
||||
*
|
||||
* If the block throws a [CancellationException], it will be rethrown.
|
||||
*/
|
||||
inline fun <A> tryOrNull(onException: ((Exception) -> Unit) = { }, operation: () -> A): A? {
|
||||
return try {
|
||||
operation()
|
||||
} catch (any: Throwable) {
|
||||
onError.invoke(any)
|
||||
} catch (e: CancellationException) {
|
||||
throw e
|
||||
} catch (e: Exception) {
|
||||
onException.invoke(e)
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,61 @@
|
||||
|
||||
package io.element.android.libraries.core.extensions
|
||||
|
||||
import kotlin.coroutines.cancellation.CancellationException
|
||||
|
||||
/**
|
||||
* Can be used to catch exceptions in a block of code and return a [Result].
|
||||
* If the block throws a [CancellationException], it will be rethrown.
|
||||
* If it throws any other exception, it will be wrapped in a [Result.failure].
|
||||
*
|
||||
* [Error]s are not caught by this function, as they are not meant to be caught in normal application flow.
|
||||
*/
|
||||
inline fun <T> runCatchingExceptions(
|
||||
block: () -> T
|
||||
): Result<T> {
|
||||
return try {
|
||||
Result.success(block())
|
||||
} catch (e: CancellationException) {
|
||||
throw e
|
||||
} catch (e: Exception) {
|
||||
Result.failure(e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to catch exceptions in a block of code and return a [Result].
|
||||
* If the block throws a [CancellationException], it will be rethrown.
|
||||
* If it throws any other exception, it will be wrapped in a [Result.failure].
|
||||
*
|
||||
* [Error]s are not caught by this function, as they are not meant to be caught in normal application flow.
|
||||
*/
|
||||
inline fun <T, R> T.runCatchingExceptions(
|
||||
block: T.() -> R
|
||||
): Result<R> {
|
||||
return try {
|
||||
Result.success(block())
|
||||
} catch (e: CancellationException) {
|
||||
throw e
|
||||
} catch (e: Exception) {
|
||||
Result.failure(e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to transform a [Result] into another [Result] by applying a [block] to the value if it is successful.
|
||||
* If the original [Result] is a failure, the exception will be wrapped in a new [Result.failure].
|
||||
*
|
||||
* This is a safer version of [Result.mapCatching].
|
||||
*/
|
||||
inline fun <R, T> Result<T>.mapCatchingExceptions(
|
||||
block: (T) -> R,
|
||||
): Result<R> {
|
||||
return fold(
|
||||
onSuccess = { value -> runCatchingExceptions { block(value) } },
|
||||
onFailure = { exception -> Result.failure(exception) }
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to transform some Throwable into some other.
|
||||
*/
|
||||
@@ -33,12 +88,16 @@ inline fun <R, T> Result<T>.flatMap(transform: (T) -> Result<R>): Result<R> {
|
||||
* @return The result of the transform or a caught exception wrapped in a [Result].
|
||||
*/
|
||||
inline fun <R, T> Result<T>.flatMapCatching(transform: (T) -> Result<R>): Result<R> {
|
||||
return mapCatching(transform).fold(
|
||||
return mapCatchingExceptions(transform).fold(
|
||||
onSuccess = { it },
|
||||
onFailure = { Result.failure(it) }
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be used to execute a block of code after the [Result] has been processed, regardless of whether it was successful or not.
|
||||
* The block receives the exception if there was one, or `null` if the result was successful.
|
||||
*/
|
||||
inline fun <T> Result<T>.finally(block: (exception: Throwable?) -> Unit): Result<T> {
|
||||
onSuccess { block(null) }
|
||||
onFailure(block)
|
||||
|
||||
Reference in New Issue
Block a user