All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jvmMain.SinksJvm.kt Maven / Gradle / Ivy

/*
 * Copyright 2017-2023 JetBrains s.r.o. and respective authors and developers.
 * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENCE file.
 */

/*
 * Copyright (C) 2014 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package kotlinx.io

import java.io.IOException
import java.io.OutputStream
import java.nio.ByteBuffer
import java.nio.channels.WritableByteChannel
import java.nio.charset.Charset

/**
 * Encodes substring of [string] starting at [startIndex] and ending at [endIndex] using [charset]
 * and writes into this sink.
 *
 * @param string the string to encode into this sink.
 * @param charset the [Charset] to use for encoding.
 * @param startIndex the index of the first character to encode, inclusive, 0 by default.
 * @param endIndex the index of the last character to encode, exclusive, `string.length` by default.
 *
 * @throws IndexOutOfBoundsException when [startIndex] or [endIndex] is out of range of [string] indices.
 * @throws IllegalArgumentException when `startIndex > endIndex`.
 * @throws IllegalStateException when the sink is closed.
 * @throws IOException when some I/O error occurs.
 *
 * @sample kotlinx.io.samples.KotlinxIoSamplesJvm.readWriteStrings
 */
public fun Sink.writeString(string: String, charset: Charset, startIndex: Int = 0, endIndex: Int = string.length) {
    checkBounds(string.length, startIndex, endIndex)
    if (charset == Charsets.UTF_8) return writeString(string, startIndex, endIndex)
    val data = string.substring(startIndex, endIndex).toByteArray(charset)
    write(data, 0, data.size)
}

/**
 * Returns an output stream that writes to this sink. Closing the stream will also close this sink.
 *
 * @sample kotlinx.io.samples.KotlinxIoSamplesJvm.asStream
 */
@OptIn(DelicateIoApi::class)
public fun Sink.asOutputStream(): OutputStream {
    val isClosed: () -> Boolean = when (this) {
        is RealSink -> this::closed
        is Buffer -> {
            { false }
        }
    }

    return object : OutputStream() {
        override fun write(byte: Int) {
            if (isClosed()) throw IOException("Underlying sink is closed.")
            writeToInternalBuffer { it.writeByte(byte.toByte()) }
        }

        override fun write(data: ByteArray, offset: Int, byteCount: Int) {
            if (isClosed()) throw IOException("Underlying sink is closed.")
            writeToInternalBuffer { it.write(data, offset, offset + byteCount) }
        }

        override fun flush() {
            // For backwards compatibility, a flush() on a closed stream is a no-op.
            if (!isClosed()) {
                [email protected]()
            }
        }

        override fun close() = [email protected]()

        override fun toString() = "${this@asOutputStream}.asOutputStream()"
    }
}

/**
 * Writes data from the [source] into this sink and returns the number of bytes written.
 *
 * @param source the source to read from.
 *
 * @throws IllegalStateException when the sink is closed.
 * @throws IOException when some I/O error occurs.
 *
 * @sample kotlinx.io.samples.KotlinxIoSamplesJvm.readWriteByteBuffer
 */
@OptIn(InternalIoApi::class)
public fun Sink.write(source: ByteBuffer): Int {
    val sizeBefore = buffer.size
    buffer.transferFrom(source)
    val bytesRead = buffer.size - sizeBefore
    hintEmit()
    return bytesRead.toInt()
}

/**
 * Returns [WritableByteChannel] backed by this sink. Closing the channel will also close the sink.
 */
public fun Sink.asByteChannel(): WritableByteChannel {
    val isClosed: () -> Boolean = when (this) {
        is RealSink -> this::closed
        is Buffer -> {
            { false }
        }
    }

    return object : WritableByteChannel {
        override fun close() {
            [email protected]()
        }

        override fun isOpen(): Boolean = !isClosed()

        override fun write(source: ByteBuffer): Int {
            check(!isClosed()) { "Underlying sink is closed." }
            return [email protected](source)
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy