Skip to content

Completable job #971

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,20 @@ public final class kotlinx/coroutines/CompletableDeferredKt {
public static synthetic fun CompletableDeferred$default (Lkotlinx/coroutines/Job;ILjava/lang/Object;)Lkotlinx/coroutines/CompletableDeferred;
}

public abstract interface class kotlinx/coroutines/CompletableJob : kotlinx/coroutines/Job {
public abstract fun complete ()Z
public abstract fun completeExceptionally (Ljava/lang/Throwable;)Z
}

public final class kotlinx/coroutines/CompletableJob$DefaultImpls {
public static synthetic fun cancel (Lkotlinx/coroutines/CompletableJob;)Z
public static fun fold (Lkotlinx/coroutines/CompletableJob;Ljava/lang/Object;Lkotlin/jvm/functions/Function2;)Ljava/lang/Object;
public static fun get (Lkotlinx/coroutines/CompletableJob;Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext$Element;
public static fun minusKey (Lkotlinx/coroutines/CompletableJob;Lkotlin/coroutines/CoroutineContext$Key;)Lkotlin/coroutines/CoroutineContext;
public static fun plus (Lkotlinx/coroutines/CompletableJob;Lkotlin/coroutines/CoroutineContext;)Lkotlin/coroutines/CoroutineContext;
public static fun plus (Lkotlinx/coroutines/CompletableJob;Lkotlinx/coroutines/Job;)Lkotlinx/coroutines/Job;
}

public final class kotlinx/coroutines/CompletionHandlerException : java/lang/RuntimeException {
public fun <init> (Ljava/lang/String;Ljava/lang/Throwable;)V
}
Expand Down Expand Up @@ -315,7 +329,9 @@ public final class kotlinx/coroutines/Job$Key : kotlin/coroutines/CoroutineConte

public final class kotlinx/coroutines/JobKt {
public static final fun DisposableHandle (Lkotlin/jvm/functions/Function0;)Lkotlinx/coroutines/DisposableHandle;
public static final fun Job (Lkotlinx/coroutines/Job;)Lkotlinx/coroutines/Job;
public static final fun Job (Lkotlinx/coroutines/Job;)Lkotlinx/coroutines/CompletableJob;
public static final synthetic fun Job (Lkotlinx/coroutines/Job;)Lkotlinx/coroutines/Job;
public static synthetic fun Job$default (Lkotlinx/coroutines/Job;ILjava/lang/Object;)Lkotlinx/coroutines/CompletableJob;
public static synthetic fun Job$default (Lkotlinx/coroutines/Job;ILjava/lang/Object;)Lkotlinx/coroutines/Job;
public static final fun cancel (Lkotlin/coroutines/CoroutineContext;)V
public static final synthetic fun cancel (Lkotlin/coroutines/CoroutineContext;)Z
Expand Down Expand Up @@ -422,7 +438,9 @@ public final class kotlinx/coroutines/RunnableKt {
}

public final class kotlinx/coroutines/SupervisorKt {
public static final fun SupervisorJob (Lkotlinx/coroutines/Job;)Lkotlinx/coroutines/Job;
public static final fun SupervisorJob (Lkotlinx/coroutines/Job;)Lkotlinx/coroutines/CompletableJob;
public static final synthetic fun SupervisorJob (Lkotlinx/coroutines/Job;)Lkotlinx/coroutines/Job;
public static synthetic fun SupervisorJob$default (Lkotlinx/coroutines/Job;ILjava/lang/Object;)Lkotlinx/coroutines/CompletableJob;
public static synthetic fun SupervisorJob$default (Lkotlinx/coroutines/Job;ILjava/lang/Object;)Lkotlinx/coroutines/Job;
public static final fun supervisorScope (Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}
Expand Down
10 changes: 9 additions & 1 deletion kotlinx-coroutines-core/common/src/CompletableDeferred.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
* Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("DEPRECATION_ERROR")

Expand All @@ -25,6 +25,10 @@ public interface CompletableDeferred<T> : Deferred<T> {
* completed as a result of this invocation and `false` otherwise (if it was already completed).
*
* Repeated invocations of this function have no effect and always produce `false`.
*
* This function transitions this deferred into _completed_ state if it was not completed or cancelled yet.
* However, if this deferred has children, then it transitions into _completing_ state and becomes _complete_
* once all its children are [complete][isCompleted]. See [Job] for details.
*/
public fun complete(value: T): Boolean

Expand All @@ -33,6 +37,10 @@ public interface CompletableDeferred<T> : Deferred<T> {
* completed as a result of this invocation and `false` otherwise (if it was already completed).
*
* Repeated invocations of this function have no effect and always produce `false`.
*
* This function transitions this deferred into _cancelled_ state if it was not completed or cancelled yet.
* However, that if this deferred has children, then it transitions into _cancelling_ state and becomes _cancelled_
* once all its children are [complete][isCompleted]. See [Job] for details.
*/
public fun completeExceptionally(exception: Throwable): Boolean
}
Expand Down
35 changes: 35 additions & 0 deletions kotlinx-coroutines-core/common/src/CompletableJob.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package kotlinx.coroutines

/**
* A job that can be completed using [complete()] function.
* It is returned by [Job()][Job] and [SupervisorJob()][SupervisorJob] constructor functions.
*/
public interface CompletableJob : Job {
/**
* Completes this job. The result is `true` if this job was completed as a result of this invocation and
* `false` otherwise (if it was already completed).
*
* Repeated invocations of this function have no effect and always produce `false`.
*
* This function transitions this job into _completed- state if it was not completed or cancelled yet.
* However, that if this job has children, then it transitions into _completing_ state and becomes _complete_
* once all its children are [complete][isCompleted]. See [Job] for details.
*/
public fun complete(): Boolean

/**
* Completes this job exceptionally with a given [exception]. The result is `true` if this job was
* completed as a result of this invocation and `false` otherwise (if it was already completed).
*
* Repeated invocations of this function have no effect and always produce `false`.
*
* This function transitions this job into _cancelled_ state if it was not completed or cancelled yet.
* However, that if this job has children, then it transitions into _cancelling_ state and becomes _cancelled_
* once all its children are [complete][isCompleted]. See [Job] for details.
*/
public fun completeExceptionally(exception: Throwable): Boolean
}
15 changes: 13 additions & 2 deletions kotlinx-coroutines-core/common/src/Job.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
* Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

@file:JvmMultifileClass
Expand Down Expand Up @@ -348,10 +348,21 @@ public interface Job : CoroutineContext.Element {
* is cancelled when its parent fails or is cancelled. All this job's children are cancelled in this case, too.
* The invocation of [cancel][Job.cancel] with exception (other than [CancellationException]) on this job also cancels parent.
*
* Conceptually, the resulting job works in the same way as the job created by the `launch { body }` invocation
* (see [launch]), but without any code in the body. It is active until cancelled or completed. Invocation of
* [CompletableJob.complete] or [CompletableJob.completeExceptionally] corresponds to the successful or
* failed completion of the body of the coroutine.
*
* @param parent an optional parent job.
*/
@Suppress("FunctionName")
public fun Job(parent: Job? = null): Job = JobImpl(parent)
public fun Job(parent: Job? = null): CompletableJob = JobImpl(parent)

/** @suppress Binary compatibility only */
@Suppress("FunctionName")
@Deprecated(level = DeprecationLevel.HIDDEN, message = "Binary compatibility")
@JvmName("Job")
public fun Job0(parent: Job? = null): Job = Job(parent)

/**
* A handle to an allocated object that can be disposed to make it eligible for garbage collection.
Expand Down
7 changes: 5 additions & 2 deletions kotlinx-coroutines-core/common/src/JobSupport.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
* Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
@file:Suppress("DEPRECATION_ERROR")

Expand Down Expand Up @@ -1182,11 +1182,14 @@ private class Empty(override val isActive: Boolean) : Incomplete {
override fun toString(): String = "Empty{${if (isActive) "Active" else "New" }}"
}

internal class JobImpl(parent: Job? = null) : JobSupport(true) {
internal open class JobImpl(parent: Job?) : JobSupport(true), CompletableJob {
init { initParentJobInternal(parent) }
override val cancelsParent: Boolean get() = true
override val onCancelComplete get() = true
override val handlesException: Boolean get() = false
override fun complete() = makeCompleting(Unit)
override fun completeExceptionally(exception: Throwable): Boolean =
makeCompleting(CompletedExceptionally(exception))
}

// -------- invokeOnCompletion nodes
Expand Down
16 changes: 9 additions & 7 deletions kotlinx-coroutines-core/common/src/Supervisor.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
* Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

@file:Suppress("DEPRECATION_ERROR")
Expand Down Expand Up @@ -28,7 +28,13 @@ import kotlin.jvm.*
* @param parent an optional parent job.
*/
@Suppress("FunctionName")
public fun SupervisorJob(parent: Job? = null) : Job = SupervisorJobImpl(parent)
public fun SupervisorJob(parent: Job? = null) : CompletableJob = SupervisorJobImpl(parent)

/** @suppress Binary compatibility only */
@Suppress("FunctionName")
@Deprecated(level = DeprecationLevel.HIDDEN, message = "Binary compatibility")
@JvmName("SupervisorJob")
public fun SupervisorJob0(parent: Job? = null) : Job = SupervisorJob(parent)

/**
* Creates new [CoroutineScope] with [SupervisorJob] and calls the specified suspend block with this scope.
Expand All @@ -46,11 +52,7 @@ public suspend fun <R> supervisorScope(block: suspend CoroutineScope.() -> R):
coroutine.startUndispatchedOrReturn(coroutine, block)
}

private class SupervisorJobImpl(parent: Job?) : JobSupport(true) {
init { initParentJobInternal(parent) }
override val cancelsParent: Boolean get() = true
override val onCancelComplete get() = true
override val handlesException: Boolean get() = false
private class SupervisorJobImpl(parent: Job?) : JobImpl(parent) {
override fun childCancelled(cause: Throwable): Boolean = false
}

Expand Down
49 changes: 49 additions & 0 deletions kotlinx-coroutines-core/common/test/CompletableJobTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package kotlinx.coroutines

import kotlin.test.*

class CompletableJobTest {
@Test
fun testComplete() {
val job = Job()
assertTrue(job.isActive)
assertFalse(job.isCompleted)
assertTrue(job.complete())
assertTrue(job.isCompleted)
assertFalse(job.isActive)
assertFalse(job.isCancelled)
assertFalse(job.complete())
}

@Test
fun testCompleteWithException() {
val job = Job()
assertTrue(job.isActive)
assertFalse(job.isCompleted)
assertTrue(job.completeExceptionally(TestException()))
assertTrue(job.isCompleted)
assertFalse(job.isActive)
assertTrue(job.isCancelled)
assertFalse(job.completeExceptionally(TestException()))
assertFalse(job.complete())
}

@Test
fun testCompleteWithChildren() {
val parent = Job()
val child = Job(parent)
assertTrue(parent.complete())
assertFalse(parent.complete())
assertTrue(parent.isActive)
assertFalse(parent.isCompleted)
assertTrue(child.complete())
assertTrue(child.isCompleted)
assertTrue(parent.isCompleted)
assertFalse(child.isActive)
assertFalse(parent.isActive)
}
}