diff --git a/CHANGELOG.md b/CHANGELOG.md index 741f98e..a49f91c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,4 +21,9 @@ - Kotlin 1.9.0 ### 1.5.3 -- Kotlin 1.9.10 \ No newline at end of file +- Kotlin 1.9.10 + +### 1.5.4 +- Add `transform()` function to map results without nesting +- Add `mapCatching()` +- Implement `equals()` and `hashCode()` \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 09a2ef5..5276ac4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,4 +5,4 @@ kotlin.native.binary.freezing=disabled kotlin.mpp.stability.nowarn=true kotlin.native.ignoreDisabledTargets=true -artifactVersion = 1.5.3 \ No newline at end of file +artifactVersion = 1.5.4 \ No newline at end of file diff --git a/src/commonMain/kotlin/at/asitplus/KmmResult.kt b/src/commonMain/kotlin/at/asitplus/KmmResult.kt index 7c50fdb..bbc72b6 100644 --- a/src/commonMain/kotlin/at/asitplus/KmmResult.kt +++ b/src/commonMain/kotlin/at/asitplus/KmmResult.kt @@ -85,6 +85,25 @@ class KmmResult private constructor( inline fun map(block: (T) -> R): KmmResult = getOrNull()?.let { success(block(it)) } ?: this as KmmResult + /** + * Transforms this KmmResult into a KmmResult of different success type according to `block` and leaves the + * failure case untouched. Avoids nested KmmResults + */ + @Suppress("UNCHECKED_CAST") + inline fun transform(block: (T) -> KmmResult): KmmResult = + getOrNull()?.let { block(it) } ?: this as KmmResult + + /** + * Returns the encapsulated result of the given [block] function applied to the encapsulated value + * if this instance represents [success][KmmResult.isSuccess] or the + * original encapsulated [Throwable] exception if it is [failure][KmmResult.isFailure]. + * + * This function catches any [Throwable] exception thrown by [block] function and encapsulates it as a failure. + * See [map] for an alternative that rethrows exceptions from `transform` function. + */ + @Suppress("UNCHECKED_CAST") + inline fun mapCatching(block: (T) -> R): KmmResult = unwrap().mapCatching { block(it) }.wrap() + /** * Transforms this KmmResult's failure-case according to `block` and leaves the success case untouched * (type erasure FTW!) @@ -134,6 +153,19 @@ class KmmResult private constructor( exName?.let { ")" } } + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || this::class != other::class) return false + + other as KmmResult<*> + + return delegate == other.delegate + } + + override fun hashCode(): Int { + return delegate.hashCode() + } + @OptIn(ExperimentalObjCRefinement::class) companion object { @HiddenFromObjC diff --git a/src/commonTest/kotlin/KmmResultTest.kt b/src/commonTest/kotlin/KmmResultTest.kt index 7cc9457..311a3ac 100644 --- a/src/commonTest/kotlin/KmmResultTest.kt +++ b/src/commonTest/kotlin/KmmResultTest.kt @@ -1,9 +1,11 @@ package at.asitplus +import at.asitplus.KmmResult.Companion.success import at.asitplus.KmmResult.Companion.wrap import kotlin.test.* class KmmResultTest { + @Test fun testMap() { assertEquals("1234", KmmResult.success(1234).map { it.toString() }.getOrThrow()) @@ -15,6 +17,16 @@ class KmmResultTest { assertEquals(9, KmmResult.success(3).map { it * 3 }.getOrThrow()) } + @Test + fun testTransform() { + val intResult = success(1234) + val stringResult = success("1234") + assertEquals(stringResult, intResult.transform { success(it.toString()) }) + val throwable = NullPointerException("Null") + val fail: KmmResult = KmmResult.failure(throwable) + assertEquals(fail, fail.transform { success( it * 3 ) }) + } + @Test fun testMapFailure() { assertTrue(