Skip to content

Commit

Permalink
k2 + non-fatal catching
Browse files Browse the repository at this point in the history
  • Loading branch information
JesusMcCloud committed Jun 3, 2024
1 parent edeeb13 commit 2a29e4c
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 25 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ build/
local.properties
!**/src/main/**/build/
!**/src/test/**/build/
.kotlin

### STS ###
.apt_generated
Expand Down
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,9 @@
### 1.5.4
- Add `transform()` function to map results without nesting
- Add `mapCatching()`
- Implement `equals()` and `hashCode()`
- Implement `equals()` and `hashCode()`

## 1.6.0
- Kotlin 2.0
- Failure re-throws any fatal and coroutine-related exceptions
- `catching` function, modelling stdlib's `runCatching`, directly returning a `KmmResult`
37 changes: 18 additions & 19 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import io.gitlab.arturbosch.detekt.Detekt
import org.gradle.kotlin.dsl.support.listFilesOrdered

plugins {
kotlin("multiplatform") version "1.9.10"
kotlin("multiplatform") version "2.0.0"
id("maven-publish")
id("signing")
id("io.github.gradle-nexus.publish-plugin") version "1.3.0"
id("org.jetbrains.dokka") version "1.8.20"
id("org.jetbrains.kotlinx.kover") version "0.7.3"
id("io.gitlab.arturbosch.detekt") version "1.23.1"
id("org.jetbrains.dokka") version "1.9.20"
id("org.jetbrains.kotlinx.kover") version "0.8.0"
id("io.gitlab.arturbosch.detekt") version "1.23.6"
}

val artifactVersion: String by extra
Expand Down Expand Up @@ -108,15 +108,12 @@ kotlin {
xcf.add(this)
}
}
ios() {
binaries.framework {
baseName = "KmmResult"
embedBitcode("bitcode")
xcf.add(this)
}
}
iosSimulatorArm64 {
binaries.framework {
listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
).forEach {
it.binaries.framework {
baseName = "KmmResult"
embedBitcode("bitcode")
xcf.add(this)
Expand All @@ -134,6 +131,7 @@ kotlin {
}
withJava() //for Java Interop tests
}

js(IR) {
browser { testTask { enabled = false } }
nodejs()
Expand All @@ -143,16 +141,17 @@ kotlin {
mingwX64()

sourceSets {
@Suppress("UNUSED_VARIABLE") val commonMain by getting
commonMain.dependencies {
implementation("io.arrow-kt:arrow-core:1.2.4")
}

@Suppress("UNUSED_VARIABLE") val commonTest by getting {
dependencies {
implementation(kotlin("test"))
}
commonTest.dependencies {
implementation(kotlin("test"))
}
}



tasks.withType<Detekt>().configureEach {
reports {
xml.required.set(true)
Expand All @@ -164,7 +163,7 @@ kotlin {
}

dependencies {
detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.21.0")
detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.23.6")
}

repositories {
Expand Down
4 changes: 1 addition & 3 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
kotlin.code.style=official
kotlin.mpp.enableCInteropCommonization=true
kotlin.native.binary.memoryModel=experimental
kotlin.native.binary.freezing=disabled
kotlin.mpp.stability.nowarn=true
kotlin.native.ignoreDisabledTargets=true

artifactVersion = 1.5.4
artifactVersion = 1.6.0
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
22 changes: 21 additions & 1 deletion src/commonMain/kotlin/at/asitplus/KmmResult.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,40 @@

package at.asitplus

import arrow.core.nonFatalOrThrow
import at.asitplus.KmmResult.Companion.wrap
import kotlin.experimental.ExperimentalObjCRefinement
import kotlin.jvm.JvmStatic
import kotlin.native.HiddenFromObjC

/**
* Swift-Friendly variant of stdlib's [Result].
* For easy use under iOS, we need a class like `Result`
* that is not a `value` class (which is unsupported in Kotlin/Native)
*
* Trying to create a failure case
* re-throws any fatal exceptions, such as `OutOfMemoryError`.
* Relies on [Arrow](https://arrow-kt.io)'s [nonFatalOrThrow](https://apidocs.arrow-kt.io/arrow-core/arrow.core/non-fatal-or-throw.html) internally.
*/
class KmmResult<T> private constructor(
class KmmResult<T>
private constructor(
private val delegate: Result<T>,
@Suppress("UNUSED_PARAMETER") unusedButPreventsSignatureClashes: Boolean
) {

init {
delegate.exceptionOrNull()?.nonFatalOrThrow()
}

/**
* Creates a success result from the given [value]
*/
constructor(value: T) : this(Result.success(value), false)

/**
* Creates a failure result from the given [failure]
* Trying to create a failure case re-throws any fatal exceptions, such as `OutOfMemoryError`.
* Relies on [Arrow](https://arrow-kt.io)'s [nonFatalOrThrow](https://apidocs.arrow-kt.io/arrow-core/arrow.core/non-fatal-or-throw.html) internally.
*/
constructor(failure: Throwable) : this(Result.failure(failure), false)

Expand Down Expand Up @@ -182,3 +196,9 @@ class KmmResult<T> private constructor(
fun <T> Result<T>.wrap(): KmmResult<T> = KmmResult(this, false)
}
}

/**
* Non-fatal-only-catching version of stdlib's [runCatching], directly returning a [KmmResult]-
* Re-throws any fatal exceptions, such as `OutOfMemoryError`. Relies on [Arrow](https://arrow-kt.io)'s [nonFatalOrThrow](https://apidocs.arrow-kt.io/arrow-core/arrow.core/non-fatal-or-throw.html) internally.
*/
inline fun <R> catching(block: () -> R): KmmResult<R> = runCatching { block() }.wrap()
27 changes: 27 additions & 0 deletions src/commonTest/kotlin/KmmResultTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,37 @@ package at.asitplus

import at.asitplus.KmmResult.Companion.success
import at.asitplus.KmmResult.Companion.wrap
import kotlin.coroutines.cancellation.CancellationException
import kotlin.test.*

class KmmResultTest {

@Test
fun testCatching() {
assertFailsWith(CancellationException::class) {
catching { throw CancellationException("just a test", null) }
}

assertFailsWith(CancellationException::class) {
runCatching { throw CancellationException("just a test", null) }.wrap()
}

assertFailsWith(CancellationException::class) {
KmmResult.failure<Unit>(CancellationException("just a test", null))
}
assertFailsWith(CancellationException::class) {
Result.failure<Unit>(CancellationException("just a test", null)).wrap()
}

runCatching { throw CancellationException("just a test", null) }
Result.failure<Unit>(CancellationException("just a test", null))
catching { throw NullPointerException("just a test") }
runCatching { throw NullPointerException("just a test") }.wrap()
KmmResult.failure<Unit>(NullPointerException("just a test"))
Result.failure<Unit>(NullPointerException("just a test")).wrap()

}

@Test
fun testMap() {
assertEquals("1234", KmmResult.success(1234).map { it.toString() }.getOrThrow())
Expand Down

0 comments on commit 2a29e4c

Please sign in to comment.