blob: 37ab97a21dacc95130ef368e301517ca3b7fd1b2 [file] [log] [blame]
Sergey Mashkov86f70612017-07-25 10:59:44 +03001package kotlinx.coroutines.experimental.io.internal
2
Roman Elizarov83762032017-08-08 19:58:40 +03003import java.nio.ByteBuffer
Sergey Mashkov86f70612017-07-25 10:59:44 +03004
Roman Elizarov83762032017-08-08 19:58:40 +03005// this is MAGICAL constant that is tied to the code ByteBufferChannel (that is how much it needs extra)
6internal const val RESERVED_SIZE = 8
Sergey Mashkov86f70612017-07-25 10:59:44 +03007
Roman Elizarov83762032017-08-08 19:58:40 +03008internal val EmptyByteBuffer: ByteBuffer = ByteBuffer.allocate(0)
Roman Elizarov469cad32017-08-15 15:54:56 +03009internal val EmptyCapacity = RingBufferCapacity(0)
Roman Elizarov83762032017-08-08 19:58:40 +030010
11internal sealed class ReadWriteBufferState(
Roman Elizarov469cad32017-08-15 15:54:56 +030012 @JvmField val backingBuffer: ByteBuffer,
13 @JvmField val capacity: RingBufferCapacity
Roman Elizarov83762032017-08-08 19:58:40 +030014) {
Sergey Mashkov86f70612017-07-25 10:59:44 +030015 open val idle: Boolean get() = false
Roman Elizarov83762032017-08-08 19:58:40 +030016 open val readBuffer: ByteBuffer get() = error("read buffer is not available in state $this")
17 open val writeBuffer: ByteBuffer get() = error("write buffer is not available in state $this")
Sergey Mashkov86f70612017-07-25 10:59:44 +030018
Roman Elizarov83762032017-08-08 19:58:40 +030019 internal open fun startReading(): ReadWriteBufferState = error("Reading is not available in state $this")
20 internal open fun startWriting(): ReadWriteBufferState = error("Writing is not available in state $this")
21 internal open fun stopReading(): ReadWriteBufferState = error("Unable to stop reading in state $this")
22 internal open fun stopWriting(): ReadWriteBufferState = error("Unable to stop writing in state $this")
Sergey Mashkov86f70612017-07-25 10:59:44 +030023
Roman Elizarov469cad32017-08-15 15:54:56 +030024 object IdleEmpty : ReadWriteBufferState(EmptyByteBuffer, EmptyCapacity) {
Sergey Mashkov86f70612017-07-25 10:59:44 +030025 override val idle: Boolean get() = true
Sergey Mashkov86f70612017-07-25 10:59:44 +030026 override fun toString() = "IDLE(empty)"
Sergey Mashkov86f70612017-07-25 10:59:44 +030027 }
28
Roman Elizarov83762032017-08-08 19:58:40 +030029 class Initial(
30 backingBuffer: ByteBuffer,
31 reservedSize: Int = RESERVED_SIZE
32 ) : ReadWriteBufferState(backingBuffer, RingBufferCapacity(backingBuffer.capacity() - reservedSize)) {
33 init {
34 require(backingBuffer.position() == 0)
35 require(backingBuffer.limit() == backingBuffer.capacity())
36 }
37 override val writeBuffer: ByteBuffer = backingBuffer.duplicate() // defensive copy of buffer's state
38 override val readBuffer: ByteBuffer = backingBuffer.duplicate() // must have a separate buffer state here
39 // all other possible states
40 internal val idleState = IdleNonEmpty(this)
41 internal val readingState = Reading(this)
42 internal val writingState = Writing(this)
43 internal val readingWritingState = ReadingWriting(this)
44 // state transitions
Sergey Mashkov86f70612017-07-25 10:59:44 +030045 override fun startReading() = readingState
46 override fun startWriting() = writingState
Sergey Mashkov86f70612017-07-25 10:59:44 +030047 override val idle: Boolean get() = error("Not available for initial state")
Sergey Mashkov86f70612017-07-25 10:59:44 +030048 override fun toString() = "Initial"
49 }
50
Roman Elizarov83762032017-08-08 19:58:40 +030051 class IdleNonEmpty internal constructor(
52 val initial: Initial // public here, so can release initial state when idle
53 ) : ReadWriteBufferState(initial.backingBuffer, initial.capacity) {
54 override fun startReading() = initial.readingState
55 override fun startWriting() = initial.writingState
Sergey Mashkov86f70612017-07-25 10:59:44 +030056 override val idle: Boolean get() = true
Sergey Mashkov86f70612017-07-25 10:59:44 +030057 override fun toString() = "IDLE(with buffer)"
58 }
59
Roman Elizarov83762032017-08-08 19:58:40 +030060 class Reading internal constructor(
61 private val initial: Initial
62 ) : ReadWriteBufferState(initial.backingBuffer, initial.capacity) {
63 override val readBuffer: ByteBuffer get() = initial.readBuffer
64 override fun startWriting() = initial.readingWritingState
65 override fun stopReading() = initial.idleState
Sergey Mashkov86f70612017-07-25 10:59:44 +030066 override fun toString() = "Reading"
67 }
68
Roman Elizarov83762032017-08-08 19:58:40 +030069 class Writing internal constructor(
70 private val initial: Initial
71 ) : ReadWriteBufferState(initial.backingBuffer, initial.capacity) {
72 override val writeBuffer: ByteBuffer get() = initial.writeBuffer
73 override fun startReading() = initial.readingWritingState
74 override fun stopWriting() = initial.idleState
Sergey Mashkov86f70612017-07-25 10:59:44 +030075 override fun toString() = "Writing"
76 }
77
Roman Elizarov83762032017-08-08 19:58:40 +030078 class ReadingWriting internal constructor(
79 private val initial: Initial
80 ) : ReadWriteBufferState(initial.backingBuffer, initial.capacity) {
81 override val readBuffer: ByteBuffer get() = initial.readBuffer
82 override val writeBuffer: ByteBuffer get() = initial.writeBuffer
83 override fun stopReading() = initial.writingState
84 override fun stopWriting() = initial.readingState
Sergey Mashkov86f70612017-07-25 10:59:44 +030085 override fun toString() = "Reading+Writing"
86 }
87
Roman Elizarov469cad32017-08-15 15:54:56 +030088 object Terminated : ReadWriteBufferState(EmptyByteBuffer, EmptyCapacity) {
Sergey Mashkov86f70612017-07-25 10:59:44 +030089 override fun toString() = "Terminated"
90 }
Roman Elizarov83762032017-08-08 19:58:40 +030091}