Skip to content

Commit

Permalink
[Gradle] Implement Future<T>.map(transform)
Browse files Browse the repository at this point in the history
^KT-59446 In Progress
  • Loading branch information
sellmair authored and qodana-bot committed Jun 20, 2023
1 parent ec46c82 commit d3d6cdc
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ internal interface CompletableFuture<T> : Future<T> {
fun complete(value: T)
}

internal fun <T, R> Future<T>.map(transform: (T) -> R): Future<R> {
return MappedFutureImpl(this, transform)
}

internal fun CompletableFuture<Unit>.complete() = complete(Unit)

/**
Expand Down Expand Up @@ -127,6 +131,38 @@ private class FutureImpl<T>(
}
}

private class MappedFutureImpl<T, R>(
private val future: Future<T>,
private var transform: (T) -> R,
) : Future<R>, Serializable {

private val value = Completable<R>()

override suspend fun await(): R {
if (value.isCompleted) return value.getCompleted()
value.complete(transform(future.await()))
transform = { throw IllegalStateException("Unexpected 'transform' in future") }
return value.getCompleted()
}

override fun getOrThrow(): R {
if (value.isCompleted) return value.getCompleted()
value.complete(transform(future.getOrThrow()))
transform = { throw IllegalStateException("Unexpected 'transform' in future") }
return value.getCompleted()
}

private fun writeReplace(): Any {
return Surrogate(getOrThrow())
}

private class Surrogate<T>(private val value: T) : Serializable {
private fun readResolve(): Any {
return FutureImpl(Completable(value))
}
}
}

private class LenientFutureImpl<T>(
private val future: Future<T>,
) : LenientFuture<T>, Serializable {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.gradle.idea.testFixtures.utils.serialize
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle.IllegalLifecycleException
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle.Stage.FinaliseDsl
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle.Stage.ReadyForExecution
import org.jetbrains.kotlin.gradle.util.buildProject
import org.jetbrains.kotlin.gradle.util.runLifecycleAwareTest
import org.jetbrains.kotlin.gradle.utils.*
Expand Down Expand Up @@ -114,4 +115,39 @@ class FutureTest {
assertEquals(1, futureInvocations.get())
}
}

@Test
fun `test - future map`() = project.runLifecycleAwareTest {
val future = project.future { "1" }
val transformInvocations = AtomicInteger(0)

val mappedFuture = future.map { value ->
transformInvocations.incrementAndGet()
value.toInt()
}

assertEquals(1, mappedFuture.await())
assertEquals(1, mappedFuture.getOrThrow())
assertEquals(1, transformInvocations.get())

val deserializedMappedFuture = mappedFuture.serialize().deserialize() as Future<*>
assertEquals(1, deserializedMappedFuture.await())
assertEquals(1, deserializedMappedFuture.getOrThrow())
}

@Test
fun `test - future map - getOrThrow - exception`() = project.runLifecycleAwareTest {
val future = project.future {
ReadyForExecution.await()
"1"
}

val mappedFuture = future.map {
it.toInt()
}

assertFailsWith<IllegalLifecycleException> { mappedFuture.getOrThrow() }
future.await()
assertEquals(1, mappedFuture.getOrThrow())
}
}

0 comments on commit d3d6cdc

Please sign in to comment.