blob: 06433edec2df0c3ad717760f016fbe48a3e5e2aa [file] [log] [blame]
Sergey Mashkove86eb082017-12-04 18:45:05 +03001package kotlinx.coroutines.experimental.io.jvm.nio
2
3import kotlinx.coroutines.experimental.io.*
4import java.nio.channels.*
5
6/**
7 * Copy up to [limit] bytes to blocking NIO [channel]. Copying to non-blocking channel requires selection and
8 * not supported. It does suspend if no data available in byte channel but may block if destination NIO channel blocks.
9 *
10 * @return number of bytes copied
11 */
12suspend fun ByteReadChannel.copyTo(channel: WritableByteChannel, limit: Long = Long.MAX_VALUE): Long {
13 require(limit >= 0L) { "Limit shouldn't be negative: $limit" }
14 if (channel is SelectableChannel && !channel.isBlocking) {
15 throw IllegalArgumentException("Non-blocking channels are not supported")
16 }
17
18 if (isClosedForRead) return 0
19
20 var copied = 0L
21 val copy = { bb: ByteBuffer ->
22 val rem = limit - copied
23
24 if (rem < bb.remaining()) {
25 val l = bb.limit()
26 bb.limit(bb.position() + rem.toInt())
27
28 while (bb.hasRemaining()) {
29 channel.write(bb)
30 }
31
32 bb.limit(l)
33 copied += rem
34 } else {
35 var written = 0L
36 while (bb.hasRemaining()) {
37 written += channel.write(bb)
38 }
39
40 copied += written
41 }
42 }
43
44 while (copied < limit) {
45 read(min = 0, block = copy)
46 if (isClosedForRead) break
47 }
48
49 return copied
50}
51
52/**
53 * Copy up to [limit] bytes to blocking [pipe]. A shortcut to copyTo function with NIO channel destination
54 *
55 * @return number of bytes were copied
56 */
57suspend fun ByteReadChannel.copyTo(pipe: Pipe, limit: Long = Long.MAX_VALUE): Long = copyTo(pipe.sink(), limit)