Add stream piping, redirecting and flushing
This commit is contained in:
parent
407c601f88
commit
14cf028bfc
8 changed files with 346 additions and 82 deletions
|
@ -24,7 +24,11 @@ package de.staropensource.engine.base.implementable.stream
|
||||||
*
|
*
|
||||||
* @since v1-alpha10
|
* @since v1-alpha10
|
||||||
*/
|
*/
|
||||||
abstract class ReadStream : Stream(streamMode = StreamMode.READ) {
|
abstract class ReadStream : Stream(
|
||||||
|
streamMode = StreamMode.READ,
|
||||||
|
autoFlushAfter = 0UL,
|
||||||
|
) {
|
||||||
override fun writeByte(byte: Byte): Stream = this
|
override fun writeByte(byte: Byte): Stream = this
|
||||||
override fun writeBytes(bytes: ByteArray): Stream = this
|
override fun writeBytes(bytes: ByteArray): Stream = this
|
||||||
|
override fun flush(): Stream = this
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,11 @@
|
||||||
|
|
||||||
package de.staropensource.engine.base.implementable.stream
|
package de.staropensource.engine.base.implementable.stream
|
||||||
|
|
||||||
|
import de.staropensource.engine.base.Engine.Companion.logger
|
||||||
import de.staropensource.engine.base.annotation.NonKotlinContact
|
import de.staropensource.engine.base.annotation.NonKotlinContact
|
||||||
import de.staropensource.engine.base.exception.io.IOAccessException
|
import de.staropensource.engine.base.exception.io.IOAccessException
|
||||||
|
import de.staropensource.engine.base.implementation.stream.JavaReadStream
|
||||||
|
import de.staropensource.engine.base.implementation.stream.JavaWriteStream
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
|
@ -29,9 +32,14 @@ import java.io.OutputStream
|
||||||
* Makes streaming data easy.
|
* Makes streaming data easy.
|
||||||
*
|
*
|
||||||
* @param streamMode supported [StreamMode]s
|
* @param streamMode supported [StreamMode]s
|
||||||
|
* @param autoFlushAfter after which amount of bytes to automatically flush. May be ignored by some implementations. Implementations should expose this argument in their constructor
|
||||||
* @since v1-alpha10
|
* @since v1-alpha10
|
||||||
*/
|
*/
|
||||||
abstract class Stream(val streamMode: StreamMode) : AutoCloseable {
|
@Suppress("Unused")
|
||||||
|
abstract class Stream(
|
||||||
|
val streamMode: StreamMode,
|
||||||
|
val autoFlushAfter: ULong = 100UL,
|
||||||
|
) : AutoCloseable {
|
||||||
/**
|
/**
|
||||||
* Companion object of [Stream].
|
* Companion object of [Stream].
|
||||||
*
|
*
|
||||||
|
@ -45,26 +53,9 @@ abstract class Stream(val streamMode: StreamMode) : AutoCloseable {
|
||||||
* @see <a href="https://man.archlinux.org/man/stdin.3">stdin(3)</a>
|
* @see <a href="https://man.archlinux.org/man/stdin.3">stdin(3)</a>
|
||||||
* @since v1-alpha10
|
* @since v1-alpha10
|
||||||
*/
|
*/
|
||||||
val standardInput: ReadStream = object : ReadStream() {
|
val standardInput: ReadStream = object : JavaReadStream(System.`in`) {
|
||||||
/**
|
|
||||||
* Contains the Java [InputStream]
|
|
||||||
* provided by [System.in].
|
|
||||||
*
|
|
||||||
* @since v1-alpha10
|
|
||||||
*/
|
|
||||||
val stream: InputStream = System.`in`
|
|
||||||
|
|
||||||
// -----> Closure
|
|
||||||
override fun close() = Unit
|
override fun close() = Unit
|
||||||
override fun closeStream() = Unit
|
override fun closeStream() = Unit
|
||||||
|
|
||||||
|
|
||||||
// -----> Reading
|
|
||||||
override fun remaining(): Boolean? = null
|
|
||||||
override fun available(): UInt = stream.available().toUInt()
|
|
||||||
override fun readNextByte(): Byte? = stream.read().toByte()
|
|
||||||
override fun readNBytes(n: UInt): ByteArray = stream.readNBytes(n.toInt())
|
|
||||||
override fun readRemainingBytes(): ByteArray = stream.readAllBytes()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -74,29 +65,9 @@ abstract class Stream(val streamMode: StreamMode) : AutoCloseable {
|
||||||
* @see <a href="https://man.archlinux.org/man/stdout.3">stdout(3)</a>
|
* @see <a href="https://man.archlinux.org/man/stdout.3">stdout(3)</a>
|
||||||
* @since v1-alpha10
|
* @since v1-alpha10
|
||||||
*/
|
*/
|
||||||
val standardOutput: WriteStream = object : WriteStream() {
|
val standardOutput: WriteStream = object : JavaWriteStream(System.out) {
|
||||||
/**
|
|
||||||
* Contains the Java [OutputStream]
|
|
||||||
* provided by [System.out].
|
|
||||||
*
|
|
||||||
* @since v1-alpha10
|
|
||||||
*/
|
|
||||||
val stream: OutputStream = System.out
|
|
||||||
|
|
||||||
// -----> Closure
|
|
||||||
override fun close() = Unit
|
override fun close() = Unit
|
||||||
override fun closeStream() = Unit
|
override fun closeStream() = Unit
|
||||||
|
|
||||||
|
|
||||||
// -----> Writing
|
|
||||||
override fun writeByte(byte: Byte): Stream {
|
|
||||||
stream.write(byte.toInt())
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
override fun writeBytes(bytes: ByteArray): Stream {
|
|
||||||
stream.write(bytes)
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -105,29 +76,9 @@ abstract class Stream(val streamMode: StreamMode) : AutoCloseable {
|
||||||
* @see <a href="https://man.archlinux.org/man/stderr.3">stderr(3)</a>
|
* @see <a href="https://man.archlinux.org/man/stderr.3">stderr(3)</a>
|
||||||
* @since v1-alpha10
|
* @since v1-alpha10
|
||||||
*/
|
*/
|
||||||
val standardError: WriteStream = object : WriteStream() {
|
val standardError: WriteStream = object : JavaWriteStream(System.err) {
|
||||||
/**
|
|
||||||
* Contains the Java [OutputStream]
|
|
||||||
* provided by [System.err].
|
|
||||||
*
|
|
||||||
* @since v1-alpha10
|
|
||||||
*/
|
|
||||||
val stream: OutputStream = System.err
|
|
||||||
|
|
||||||
// -----> Closure
|
|
||||||
override fun close() = Unit
|
override fun close() = Unit
|
||||||
override fun closeStream() = Unit
|
override fun closeStream() = Unit
|
||||||
|
|
||||||
|
|
||||||
// -----> Writing
|
|
||||||
override fun writeByte(byte: Byte): Stream {
|
|
||||||
stream.write(byte.toInt())
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
override fun writeBytes(bytes: ByteArray): Stream {
|
|
||||||
stream.write(bytes)
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,6 +92,46 @@ abstract class Stream(val streamMode: StreamMode) : AutoCloseable {
|
||||||
var closed: Boolean = false
|
var closed: Boolean = false
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether this stream
|
||||||
|
* is currently being [watch]ed.
|
||||||
|
*
|
||||||
|
* @since v1-alpha10
|
||||||
|
*/
|
||||||
|
var watching: Boolean = false
|
||||||
|
private set
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains a list of [Stream]s
|
||||||
|
* to redirect writes to.
|
||||||
|
*
|
||||||
|
* Redirecting is only performed
|
||||||
|
* upon invoking either [writeByte],
|
||||||
|
* [writeBytes], [writeString] or
|
||||||
|
* [write].
|
||||||
|
*
|
||||||
|
* @see pipes
|
||||||
|
* @since v1-alpha10
|
||||||
|
*/
|
||||||
|
val redirects: MutableList<Stream> = mutableListOf()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains a list of [Stream]s
|
||||||
|
* to pipe reads to.
|
||||||
|
*
|
||||||
|
* Piping is only performed upon
|
||||||
|
* invoking either [readNextByte],
|
||||||
|
* [readNBytes] or
|
||||||
|
* [readRemainingBytes].
|
||||||
|
*
|
||||||
|
* To watch for changes, see [watch].
|
||||||
|
*
|
||||||
|
* @see redirects
|
||||||
|
* @see watch
|
||||||
|
* @since v1-alpha10
|
||||||
|
*/
|
||||||
|
val pipes: MutableList<Stream> = mutableListOf()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains the Java [InputStream]
|
* Contains the Java [InputStream]
|
||||||
* for this [Stream] instance.
|
* for this [Stream] instance.
|
||||||
|
@ -199,6 +190,12 @@ abstract class Stream(val streamMode: StreamMode) : AutoCloseable {
|
||||||
* override fun writeByte(byte: Byte): Stream = writeBytes(byteArrayOf(byte))
|
* override fun writeByte(byte: Byte): Stream = writeBytes(byteArrayOf(byte))
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
|
* Implementations should make sure
|
||||||
|
* to call [internalRedirect] before
|
||||||
|
* returning from this method to
|
||||||
|
* ensure that the written [Byte]
|
||||||
|
* is piped to all registered [pipes].
|
||||||
|
*
|
||||||
* @param byte [Byte] to write
|
* @param byte [Byte] to write
|
||||||
* @return this instance
|
* @return this instance
|
||||||
* @throws IOAccessException on IO error
|
* @throws IOAccessException on IO error
|
||||||
|
@ -211,6 +208,12 @@ abstract class Stream(val streamMode: StreamMode) : AutoCloseable {
|
||||||
* Writes (or rather: appends)
|
* Writes (or rather: appends)
|
||||||
* the specified [Byte]s.
|
* the specified [Byte]s.
|
||||||
*
|
*
|
||||||
|
* Implementations should make sure
|
||||||
|
* to call [internalRedirect] before
|
||||||
|
* returning from this method to
|
||||||
|
* ensure that the written [Byte]s
|
||||||
|
* is piped to all registered [pipes].
|
||||||
|
*
|
||||||
* @param bytes [Byte]s to write
|
* @param bytes [Byte]s to write
|
||||||
* @return this instance
|
* @return this instance
|
||||||
* @throws IOAccessException on IO error
|
* @throws IOAccessException on IO error
|
||||||
|
@ -243,6 +246,17 @@ abstract class Stream(val streamMode: StreamMode) : AutoCloseable {
|
||||||
@Throws(IOAccessException::class)
|
@Throws(IOAccessException::class)
|
||||||
fun write(value: Any): Stream = writeBytes(value.toString().toByteArray())
|
fun write(value: Any): Stream = writeBytes(value.toString().toByteArray())
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flushes all currently
|
||||||
|
* buffered bytes out.
|
||||||
|
*
|
||||||
|
* @return this instance
|
||||||
|
* @throws IOAccessException on IO error
|
||||||
|
* @since v1-alpha10
|
||||||
|
*/
|
||||||
|
@Throws(IOAccessException::class)
|
||||||
|
abstract fun flush(): Stream
|
||||||
|
|
||||||
|
|
||||||
// -----> Reading
|
// -----> Reading
|
||||||
/**
|
/**
|
||||||
|
@ -278,6 +292,8 @@ abstract class Stream(val streamMode: StreamMode) : AutoCloseable {
|
||||||
/**
|
/**
|
||||||
* Reads the next [Byte].
|
* Reads the next [Byte].
|
||||||
*
|
*
|
||||||
|
* Will not block the execution flow.
|
||||||
|
*
|
||||||
* @return next [Byte] or `null` if no bytes are remaining
|
* @return next [Byte] or `null` if no bytes are remaining
|
||||||
* @throws IOAccessException on IO error
|
* @throws IOAccessException on IO error
|
||||||
* @since v1-alpha10
|
* @since v1-alpha10
|
||||||
|
@ -288,6 +304,9 @@ abstract class Stream(val streamMode: StreamMode) : AutoCloseable {
|
||||||
/**
|
/**
|
||||||
* Reads the specified next [n] [Byte]s.
|
* Reads the specified next [n] [Byte]s.
|
||||||
*
|
*
|
||||||
|
* May block the execution flow
|
||||||
|
* until [n] bytes have been read.
|
||||||
|
*
|
||||||
* @param n [Byte]s to read
|
* @param n [Byte]s to read
|
||||||
* @return next [n] bytes or an empty array if no bytes are remaining
|
* @return next [n] bytes or an empty array if no bytes are remaining
|
||||||
* @throws IOAccessException on IO error
|
* @throws IOAccessException on IO error
|
||||||
|
@ -299,6 +318,10 @@ abstract class Stream(val streamMode: StreamMode) : AutoCloseable {
|
||||||
/**
|
/**
|
||||||
* Reads all remaining [Byte]s.
|
* Reads all remaining [Byte]s.
|
||||||
*
|
*
|
||||||
|
* May block the execution flow
|
||||||
|
* until all remaining bytes
|
||||||
|
* have been read.
|
||||||
|
*
|
||||||
* @return remaining [Byte]s or an empty array if no bytes are remaining
|
* @return remaining [Byte]s or an empty array if no bytes are remaining
|
||||||
* @throws IOAccessException on IO error
|
* @throws IOAccessException on IO error
|
||||||
* @since v1-alpha10
|
* @since v1-alpha10
|
||||||
|
@ -309,6 +332,8 @@ abstract class Stream(val streamMode: StreamMode) : AutoCloseable {
|
||||||
/**
|
/**
|
||||||
* Discards the next [Byte].
|
* Discards the next [Byte].
|
||||||
*
|
*
|
||||||
|
* Will not block the execution flow.
|
||||||
|
*
|
||||||
* @return this instance
|
* @return this instance
|
||||||
* @throws IOAccessException on IO error
|
* @throws IOAccessException on IO error
|
||||||
* @since v1-alpha10
|
* @since v1-alpha10
|
||||||
|
@ -322,6 +347,9 @@ abstract class Stream(val streamMode: StreamMode) : AutoCloseable {
|
||||||
/**
|
/**
|
||||||
* Discards the specified next [n] bytes.
|
* Discards the specified next [n] bytes.
|
||||||
*
|
*
|
||||||
|
* May block the execution flow
|
||||||
|
* until [n] bytes have been skipped.
|
||||||
|
*
|
||||||
* @param n [Byte]s to discard
|
* @param n [Byte]s to discard
|
||||||
* @return this instance
|
* @return this instance
|
||||||
* @throws IOAccessException on IO error
|
* @throws IOAccessException on IO error
|
||||||
|
@ -336,6 +364,10 @@ abstract class Stream(val streamMode: StreamMode) : AutoCloseable {
|
||||||
/**
|
/**
|
||||||
* Discards all remaining [Byte]s.
|
* Discards all remaining [Byte]s.
|
||||||
*
|
*
|
||||||
|
* May block the execution flow
|
||||||
|
* until all remaining bytes
|
||||||
|
* have been skipped.
|
||||||
|
*
|
||||||
* @return this instance
|
* @return this instance
|
||||||
* @throws IOAccessException on IO error
|
* @throws IOAccessException on IO error
|
||||||
* @since v1-alpha10
|
* @since v1-alpha10
|
||||||
|
@ -347,19 +379,151 @@ abstract class Stream(val streamMode: StreamMode) : AutoCloseable {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// -----> Redirection
|
// -----> Watching
|
||||||
/**
|
/**
|
||||||
* Reads the next byte of this
|
* Starts a thread solely responsible
|
||||||
* [Stream] and writes it
|
* for reading bytes continuously
|
||||||
* to the specified [Stream].
|
* until either [stopWatching] is
|
||||||
|
* called or this [Stream] is closed.
|
||||||
*
|
*
|
||||||
* @param stream stream to write to
|
* This method will not block the
|
||||||
|
* flow of execution.
|
||||||
|
*
|
||||||
|
* Using this method is very useful
|
||||||
|
* if wanting to only pipe the bytes
|
||||||
|
* of this [Stream] to other streams.
|
||||||
|
*
|
||||||
|
* @param threshold amount of bytes to be read before terminating or `0` to watch indefinitely
|
||||||
* @return this instance
|
* @return this instance
|
||||||
* @throws IOAccessException on IO error
|
* @throws IOAccessException on IO error
|
||||||
* @since v1-alpha10
|
* @since v1-alpha10
|
||||||
*/
|
*/
|
||||||
@Throws(IOAccessException::class)
|
@Throws(IOAccessException::class)
|
||||||
fun writeNextByteTo(stream: Stream): Stream {
|
fun watch(): Stream {
|
||||||
|
if (watching)
|
||||||
|
return this
|
||||||
|
|
||||||
|
watching = true
|
||||||
|
|
||||||
|
Thread
|
||||||
|
.ofVirtual()
|
||||||
|
.name("Stream watch thread for Stream ${javaClass.name}#${hashCode()}")
|
||||||
|
.uncaughtExceptionHandler { thread, ueh -> logger.crash("Unable to watch Stream ${javaClass.name}#${hashCode()}", throwable = ueh.cause, fatal = true) }
|
||||||
|
.start {
|
||||||
|
while (!closed && watching)
|
||||||
|
skipNextByte()
|
||||||
|
}
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops the running watching thread.
|
||||||
|
*
|
||||||
|
* @return this instance
|
||||||
|
* @since v1-alpha10
|
||||||
|
*/
|
||||||
|
fun stopWatching(): Stream {
|
||||||
|
watching = false
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// -----> Piping
|
||||||
|
/**
|
||||||
|
* Redirects the specified byte
|
||||||
|
* to all registered [redirects].
|
||||||
|
*
|
||||||
|
* Make sure to call this method
|
||||||
|
* before returning from
|
||||||
|
* [writeByte] and [writeBytes].
|
||||||
|
*
|
||||||
|
* @param byte [Byte] to redirect
|
||||||
|
* @return supplied [Byte]
|
||||||
|
* @throws IOAccessException on IO error
|
||||||
|
* @since v1-alpha10
|
||||||
|
*/
|
||||||
|
@Throws(IOAccessException::class)
|
||||||
|
protected fun internalRedirect(byte: Byte): Byte {
|
||||||
|
pipes.forEach { stream -> stream.writeByte(byte) }
|
||||||
|
return byte
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redirects the specified bytes
|
||||||
|
* to all registered [redirects].
|
||||||
|
*
|
||||||
|
* Make sure to call this method
|
||||||
|
* before returning from
|
||||||
|
* [writeByte] and [writeBytes].
|
||||||
|
*
|
||||||
|
* @param bytes [ByteArray] to redirect
|
||||||
|
* @return supplied [ByteArray]
|
||||||
|
* @throws IOAccessException on IO error
|
||||||
|
* @since v1-alpha10
|
||||||
|
*/
|
||||||
|
@Throws(IOAccessException::class)
|
||||||
|
protected fun internalRedirect(bytes: ByteArray): ByteArray {
|
||||||
|
pipes.forEach { stream -> stream.writeBytes(bytes) }
|
||||||
|
return bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pipes the specified byte.
|
||||||
|
*
|
||||||
|
* Make sure to call this method
|
||||||
|
* before returning from
|
||||||
|
* [readBytes], [readNBytes]
|
||||||
|
* and [readRemainingBytes].
|
||||||
|
*
|
||||||
|
* @param byte [Byte] to pipe
|
||||||
|
* @return supplied [Byte]
|
||||||
|
* @throws IOAccessException on IO error
|
||||||
|
* @since v1-alpha10
|
||||||
|
*/
|
||||||
|
@Throws(IOAccessException::class)
|
||||||
|
protected fun internalPipe(byte: Byte): Byte {
|
||||||
|
pipes.forEach { stream -> stream.writeByte(byte) }
|
||||||
|
return byte
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pipes the specified bytes
|
||||||
|
* to all registered [pipes].
|
||||||
|
*
|
||||||
|
* Make sure to call this method
|
||||||
|
* before returning from
|
||||||
|
* [readBytes], [readNBytes]
|
||||||
|
* and [readRemainingBytes].
|
||||||
|
*
|
||||||
|
* @param bytes [ByteArray] to pipe
|
||||||
|
* @return supplied [ByteArray]
|
||||||
|
* @throws IOAccessException on IO error
|
||||||
|
* @since v1-alpha10
|
||||||
|
*/
|
||||||
|
@Throws(IOAccessException::class)
|
||||||
|
protected fun internalPipe(bytes: ByteArray): ByteArray {
|
||||||
|
pipes.forEach { stream -> stream.writeBytes(bytes) }
|
||||||
|
return bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the next byte of this
|
||||||
|
* [Stream] and pipes it into
|
||||||
|
* the specified [Stream].
|
||||||
|
*
|
||||||
|
* Will not block the execution flow.
|
||||||
|
*
|
||||||
|
* Will not pipe `null` if
|
||||||
|
* [readNextByte] returns it.
|
||||||
|
*
|
||||||
|
* @param stream [Stream] to write to
|
||||||
|
* @return this instance
|
||||||
|
* @throws IOAccessException on IO error
|
||||||
|
* @since v1-alpha10
|
||||||
|
*/
|
||||||
|
@Throws(IOAccessException::class)
|
||||||
|
fun pipeNextByteTo(stream: Stream): Stream {
|
||||||
val byte: Byte? = readNextByte()
|
val byte: Byte? = readNextByte()
|
||||||
|
|
||||||
if (byte != null)
|
if (byte != null)
|
||||||
|
@ -370,37 +534,110 @@ abstract class Stream(val streamMode: StreamMode) : AutoCloseable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the next [n] byte of this
|
* Reads the next [n] byte of this
|
||||||
* [Stream] and writes it
|
* [Stream] and pipes it into
|
||||||
* to the specified [Stream].
|
* the specified [Stream].
|
||||||
*
|
*
|
||||||
* @param stream stream to write to
|
* May block the execution flow
|
||||||
|
* until [n] bytes have been piped.
|
||||||
|
*
|
||||||
|
* @param stream [Stream] to write to
|
||||||
* @return this instance
|
* @return this instance
|
||||||
* @throws IOAccessException on IO error
|
* @throws IOAccessException on IO error
|
||||||
* @since v1-alpha10
|
* @since v1-alpha10
|
||||||
*/
|
*/
|
||||||
@Throws(IOAccessException::class)
|
@Throws(IOAccessException::class)
|
||||||
fun writeNBytesTo(stream: Stream, n: UInt): Stream {
|
fun pipeNBytesTo(stream: Stream, n: UInt): Stream {
|
||||||
stream.writeBytes(readNBytes(n))
|
stream.writeBytes(readNBytes(n))
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads all bytes of this
|
* Reads all bytes of this
|
||||||
* [Stream] and writes
|
* [Stream] and pipes them
|
||||||
* them to the specified
|
* into the specified [Stream].
|
||||||
* [Stream].
|
|
||||||
*
|
*
|
||||||
* @param stream stream to write to
|
* May block the execution flow
|
||||||
|
* until all remaining bytes
|
||||||
|
* have been piped.
|
||||||
|
*
|
||||||
|
* @param stream [Stream] to write to
|
||||||
* @return this instance
|
* @return this instance
|
||||||
* @throws IOAccessException on IO error
|
* @throws IOAccessException on IO error
|
||||||
* @since v1-alpha10
|
* @since v1-alpha10
|
||||||
*/
|
*/
|
||||||
@Throws(IOAccessException::class)
|
@Throws(IOAccessException::class)
|
||||||
fun writeRemainingBytesTo(stream: Stream): Stream {
|
fun pipeRemainingBytesTo(stream: Stream): Stream {
|
||||||
stream.writeBytes(readRemainingBytes())
|
stream.writeBytes(readRemainingBytes())
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the next byte of this
|
||||||
|
* [Stream] and pipes it into
|
||||||
|
* the specified [Stream]s.
|
||||||
|
*
|
||||||
|
* Will not block the execution flow.
|
||||||
|
*
|
||||||
|
* Will not pipe `null` if
|
||||||
|
* [readNextByte] returns it.
|
||||||
|
*
|
||||||
|
* @param streams array of [Stream]s to write to
|
||||||
|
* @return this instance
|
||||||
|
* @throws IOAccessException on IO error
|
||||||
|
* @since v1-alpha10
|
||||||
|
*/
|
||||||
|
@Throws(IOAccessException::class)
|
||||||
|
fun pipeNextByteTo(streams: Array<Stream>): Stream {
|
||||||
|
val byte: Byte? = readNextByte()
|
||||||
|
|
||||||
|
if (byte != null)
|
||||||
|
streams.forEach { stream -> stream.writeByte(byte) }
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the next [n] byte of this
|
||||||
|
* [Stream] and pipes it into
|
||||||
|
* the specified [Stream]s.
|
||||||
|
*
|
||||||
|
* May block the execution flow
|
||||||
|
* until [n] bytes have been piped.
|
||||||
|
*
|
||||||
|
* @param streams array of [Stream]s to write to
|
||||||
|
* @return this instance
|
||||||
|
* @throws IOAccessException on IO error
|
||||||
|
* @since v1-alpha10
|
||||||
|
*/
|
||||||
|
@Throws(IOAccessException::class)
|
||||||
|
fun pipeNBytesTo(streams: Array<Stream>, n: UInt): Stream {
|
||||||
|
val bytes: ByteArray = readNBytes(n)
|
||||||
|
streams.forEach { stream -> stream.writeBytes(bytes) }
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads all bytes of this
|
||||||
|
* [Stream] and pipes them
|
||||||
|
* into the specified [Stream]s.
|
||||||
|
*
|
||||||
|
* May block the execution flow
|
||||||
|
* until all remaining bytes
|
||||||
|
* have been piped.
|
||||||
|
*
|
||||||
|
* @param streams array of [Stream]s to write to
|
||||||
|
* @return this instance
|
||||||
|
* @throws IOAccessException on IO error
|
||||||
|
* @since v1-alpha10
|
||||||
|
*/
|
||||||
|
@Throws(IOAccessException::class)
|
||||||
|
fun pipeRemainingBytesTo(streams: Array<Stream>): Stream {
|
||||||
|
val bytes: ByteArray = readRemainingBytes()
|
||||||
|
|
||||||
|
streams.forEach { stream -> stream.writeBytes(bytes) }
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// -----> Java interoperability
|
// -----> Java interoperability
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -22,9 +22,15 @@ package de.staropensource.engine.base.implementable.stream
|
||||||
/**
|
/**
|
||||||
* A write-only [Stream].
|
* A write-only [Stream].
|
||||||
*
|
*
|
||||||
|
* @param autoFlushAfter after which amount of bytes to automatically flush. May be ignored by some implementations. Implementations should expose this argument in their constructor
|
||||||
* @since v1-alpha10
|
* @since v1-alpha10
|
||||||
*/
|
*/
|
||||||
abstract class WriteStream : Stream(streamMode = StreamMode.WRITE) {
|
abstract class WriteStream(
|
||||||
|
autoFlushAfter: ULong = 100UL,
|
||||||
|
) : Stream(
|
||||||
|
streamMode = StreamMode.WRITE,
|
||||||
|
autoFlushAfter = autoFlushAfter,
|
||||||
|
) {
|
||||||
override fun remaining(): Boolean = false
|
override fun remaining(): Boolean = false
|
||||||
override fun available(): UInt = 0u
|
override fun available(): UInt = 0u
|
||||||
override fun readNextByte(): Byte? = 0x00
|
override fun readNextByte(): Byte? = 0x00
|
||||||
|
|
|
@ -72,6 +72,8 @@ open class ByteStream(val bytesRead: ByteArray) : Stream(streamMode = StreamMode
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun flush(): Stream = this
|
||||||
|
|
||||||
|
|
||||||
// -----> Reading
|
// -----> Reading
|
||||||
override fun remaining(): Boolean? {
|
override fun remaining(): Boolean? {
|
||||||
|
|
|
@ -29,7 +29,9 @@ import de.staropensource.engine.base.implementable.stream.WriteStream
|
||||||
*
|
*
|
||||||
* @since v1-alpha10
|
* @since v1-alpha10
|
||||||
*/
|
*/
|
||||||
open class ByteWriteStream : WriteStream() {
|
open class ByteWriteStream : WriteStream(
|
||||||
|
autoFlushAfter = 0UL,
|
||||||
|
) {
|
||||||
/**
|
/**
|
||||||
* Contains the bytes written
|
* Contains the bytes written
|
||||||
* to this stream.
|
* to this stream.
|
||||||
|
@ -60,4 +62,6 @@ open class ByteWriteStream : WriteStream() {
|
||||||
bytesWritten = bytesWritten.plus(bytes)
|
bytesWritten = bytesWritten.plus(bytes)
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun flush(): Stream = this
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,8 @@ class FileAccessStream internal constructor(val file: FileAccess) : Stream(strea
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun flush(): Stream = this
|
||||||
|
|
||||||
|
|
||||||
// -----> Reading
|
// -----> Reading
|
||||||
override fun remaining(): Boolean? = null
|
override fun remaining(): Boolean? = null
|
||||||
|
|
|
@ -36,7 +36,9 @@ import de.staropensource.engine.base.utility.FileAccess
|
||||||
* @see FileAccess.toStream
|
* @see FileAccess.toStream
|
||||||
* @since v1-alpha10
|
* @since v1-alpha10
|
||||||
*/
|
*/
|
||||||
class LoggerStream internal constructor(val logger: Logger, val level: Level) : WriteStream() {
|
class LoggerStream internal constructor(val logger: Logger, val level: Level) : WriteStream(
|
||||||
|
autoFlushAfter = 0UL,
|
||||||
|
) {
|
||||||
/**
|
/**
|
||||||
* Contains the current line.
|
* Contains the current line.
|
||||||
*
|
*
|
||||||
|
@ -58,15 +60,21 @@ class LoggerStream internal constructor(val logger: Logger, val level: Level) :
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun flush(): Stream {
|
||||||
|
checkAndPrint(skipCheck = true)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verifies whether [line]
|
* Verifies whether [line]
|
||||||
* contains a newline and
|
* contains a newline and
|
||||||
* if so, prints it.
|
* if so, prints it.
|
||||||
*
|
*
|
||||||
|
* @param skipCheck if to skip the newline check
|
||||||
* @since v1-alpha10
|
* @since v1-alpha10
|
||||||
*/
|
*/
|
||||||
private fun checkAndPrint() {
|
private fun checkAndPrint(skipCheck: Boolean = false) {
|
||||||
if (line.contains("\n")) {
|
if (skipCheck || line.contains("\n")) {
|
||||||
var lineFinal: String = line.toString()
|
var lineFinal: String = line.toString()
|
||||||
|
|
||||||
// Remove last newline
|
// Remove last newline
|
||||||
|
|
|
@ -48,6 +48,7 @@ class NullStream private constructor() : Stream(streamMode = StreamMode.READ_WRI
|
||||||
|
|
||||||
override fun writeByte(byte: Byte): Stream = this
|
override fun writeByte(byte: Byte): Stream = this
|
||||||
override fun writeBytes(bytes: ByteArray): Stream = this
|
override fun writeBytes(bytes: ByteArray): Stream = this
|
||||||
|
override fun flush(): Stream = this
|
||||||
|
|
||||||
override fun remaining(): Boolean = false
|
override fun remaining(): Boolean = false
|
||||||
override fun available(): UInt = 0u
|
override fun available(): UInt = 0u
|
||||||
|
|
Loading…
Reference in a new issue