blob: 33e3d71c1559eef4bbeb8ead3452c2e27e3c689d [file] [log] [blame]
Roman Elizarovd82b3a92017-06-23 21:52:08 +03001/*
2 * Copyright 2016-2017 JetBrains s.r.o.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package kotlinx.coroutines.experimental
18
19import kotlin.coroutines.experimental.Continuation
20import kotlin.coroutines.experimental.CoroutineContext
21
22/**
23 * Abstract class to simplify writing of coroutine completion objects that
24 * implement completion [Continuation], [Job], and [CoroutineScope] interfaces.
25 * It stores the result of continuation in the state of the job.
26 *
27 * @param active when `true` coroutine is created in _active_ state, when `false` in _new_ state. See [Job] for details.
28 * @suppress **This is unstable API and it is subject to change.**
29 */
30public abstract class AbstractCoroutine<in T>(
31 private val parentContext: CoroutineContext,
32 active: Boolean
33) : JobSupport(active), Continuation<T>, CoroutineScope {
34 @Suppress("LeakingThis")
35 public final override val context: CoroutineContext = parentContext + this
36
37 final override val hasCancellingState: Boolean get() = true
38
39 final override fun resume(value: T) {
40 lockFreeLoopOnState { state ->
41 when (state) {
42 is Incomplete -> if (updateState(state, value, MODE_ATOMIC_DEFAULT)) return
43 is Cancelled -> return // ignore resumes on cancelled continuation
44 else -> error("Already resumed, but got value $value")
45 }
46 }
47 }
48
49 final override fun resumeWithException(exception: Throwable) {
50 lockFreeLoopOnState { state ->
51 when (state) {
52 is Incomplete -> {
53 if (updateState(state, CompletedExceptionally(exception), MODE_ATOMIC_DEFAULT)) return
54 }
55 is Cancelled -> {
56 // ignore resumes on cancelled continuation, but handle exception if a different one is here
57 if (exception != state.exception) handleCoroutineException(context, exception)
58 return
59 }
60 else -> throw IllegalStateException("Already resumed, but got exception $exception", exception)
61 }
62 }
63 }
64
65 final override fun handleException(exception: Throwable) {
66 handleCoroutineException(parentContext, exception)
67 }
68}