blob: f9865c2d16695e8baaf2b817e9cb41aaaa042282 [file] [log] [blame]
/*
* Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.coroutines.experimental.io.internal
import java.nio.ByteBuffer
// this is MAGICAL constant that is tied to the code ByteBufferChannel (that is how much it needs extra)
internal const val RESERVED_SIZE = 8
internal val EmptyByteBuffer: ByteBuffer = ByteBuffer.allocate(0)
internal val EmptyCapacity = RingBufferCapacity(0)
internal sealed class ReadWriteBufferState(
@JvmField val backingBuffer: ByteBuffer,
@JvmField val capacity: RingBufferCapacity
) {
open val idle: Boolean get() = false
open val readBuffer: ByteBuffer get() = error("read buffer is not available in state $this")
open val writeBuffer: ByteBuffer get() = error("write buffer is not available in state $this")
internal open fun startReading(): ReadWriteBufferState = error("Reading is not available in state $this")
internal open fun startWriting(): ReadWriteBufferState = error("Writing is not available in state $this")
internal open fun stopReading(): ReadWriteBufferState = error("Unable to stop reading in state $this")
internal open fun stopWriting(): ReadWriteBufferState = error("Unable to stop writing in state $this")
object IdleEmpty : ReadWriteBufferState(EmptyByteBuffer, EmptyCapacity) {
override val idle: Boolean get() = true
override fun toString() = "IDLE(empty)"
}
class Initial(
backingBuffer: ByteBuffer,
reservedSize: Int = RESERVED_SIZE
) : ReadWriteBufferState(backingBuffer, RingBufferCapacity(backingBuffer.capacity() - reservedSize)) {
init {
require(backingBuffer.position() == 0)
require(backingBuffer.limit() == backingBuffer.capacity())
}
override val writeBuffer: ByteBuffer = backingBuffer.duplicate() // defensive copy of buffer's state
override val readBuffer: ByteBuffer = backingBuffer.duplicate() // must have a separate buffer state here
// all other possible states
internal val idleState = IdleNonEmpty(this)
internal val readingState = Reading(this)
internal val writingState = Writing(this)
internal val readingWritingState = ReadingWriting(this)
// state transitions
override fun startReading() = readingState
override fun startWriting() = writingState
override val idle: Boolean get() = error("Not available for initial state")
override fun toString() = "Initial"
}
class IdleNonEmpty internal constructor(
val initial: Initial // public here, so can release initial state when idle
) : ReadWriteBufferState(initial.backingBuffer, initial.capacity) {
override fun startReading() = initial.readingState
override fun startWriting() = initial.writingState
override val idle: Boolean get() = true
override fun toString() = "IDLE(with buffer)"
}
class Reading internal constructor(
private val initial: Initial
) : ReadWriteBufferState(initial.backingBuffer, initial.capacity) {
override val readBuffer: ByteBuffer get() = initial.readBuffer
override fun startWriting() = initial.readingWritingState
override fun stopReading() = initial.idleState
override fun toString() = "Reading"
}
class Writing internal constructor(
private val initial: Initial
) : ReadWriteBufferState(initial.backingBuffer, initial.capacity) {
override val writeBuffer: ByteBuffer get() = initial.writeBuffer
override fun startReading() = initial.readingWritingState
override fun stopWriting() = initial.idleState
override fun toString() = "Writing"
}
class ReadingWriting internal constructor(
private val initial: Initial
) : ReadWriteBufferState(initial.backingBuffer, initial.capacity) {
override val readBuffer: ByteBuffer get() = initial.readBuffer
override val writeBuffer: ByteBuffer get() = initial.writeBuffer
override fun stopReading() = initial.writingState
override fun stopWriting() = initial.readingState
override fun toString() = "Reading+Writing"
}
object Terminated : ReadWriteBufferState(EmptyByteBuffer, EmptyCapacity) {
override fun toString() = "Terminated"
}
}