Migrate DataSize and Stream
Some checks failed
PRs & Pushes / test (push) Failing after 1m40s
PRs & Pushes / build-jars (push) Failing after 1m49s
PRs & Pushes / build-apidoc (push) Failing after 2m2s

This commit is contained in:
JeremyStar™ 2024-12-28 19:20:35 +01:00
parent 06b279e8b6
commit a5a7b8841c
Signed by: JeremyStarTM
GPG key ID: E366BAEF67E4704D
7 changed files with 316 additions and 154 deletions

View file

@ -0,0 +1,36 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU General Public License v3.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.implementable
/**
* Interface for platform-specific data.
*
* @since v1-alpha10
*/
interface PlatformData {
/**
* Contains platform-specific data.
*
* **DO NOT VIEW OR MODIFY.**
*
* @since v1-alpha10
*/
val platformData: MutableMap<String, Any?>
}

View file

@ -19,14 +19,13 @@
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.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.InputStream
import java.io.OutputStream
import de.staropensource.engine.base.implementable.PlatformData
import de.staropensource.engine.base.platform.StreamPlatform
import de.staropensource.engine.base.platform.streamPlatform
import de.staropensource.engine.base.platform.streamStandardError
import de.staropensource.engine.base.platform.streamStandardInput
import de.staropensource.engine.base.platform.streamStandardOutput
/**
* Makes streaming data easy.
@ -40,7 +39,7 @@ import java.io.OutputStream
abstract class Stream(
val streamMode: StreamMode,
val autoFlushAfter: ULong = 100UL,
) : AutoCloseable {
) : AutoCloseable, PlatformData {
/**
* Companion object of [Stream].
*
@ -54,10 +53,7 @@ abstract class Stream(
* @see <a href="https://man.archlinux.org/man/stdin.3">stdin(3)</a>
* @since v1-alpha10
*/
val standardInput: ReadStream = object : JavaReadStream(System.`in`) {
override fun close() = Unit
override fun closeStream() = Unit
}
val standardInput: ReadStream = streamStandardInput()
/**
* Contains the standard output as a [Stream].
@ -66,10 +62,7 @@ abstract class Stream(
* @see <a href="https://man.archlinux.org/man/stdout.3">stdout(3)</a>
* @since v1-alpha10
*/
val standardOutput: WriteStream = object : JavaWriteStream(System.out) {
override fun close() = Unit
override fun closeStream() = Unit
}
val standardOutput: WriteStream = streamStandardOutput()
/**
* Contains the standard error as a [Stream].
@ -77,14 +70,14 @@ abstract class Stream(
* @see <a href="https://man.archlinux.org/man/stderr.3">stderr(3)</a>
* @since v1-alpha10
*/
val standardError: WriteStream = object : JavaWriteStream(System.err) {
override fun close() = Unit
override fun closeStream() = Unit
}
val standardError: WriteStream = streamStandardError()
}
// -----> Properties
override val platformData: MutableMap<String, Any?> = mutableMapOf()
private val platform: StreamPlatform = streamPlatform(this)
/**
* Indicates whether this stream is closed.
*
@ -133,22 +126,6 @@ abstract class Stream(
*/
val pipes: MutableList<Stream> = mutableListOf()
/**
* Contains the Java [InputStream]
* for this [Stream] instance.
*
* @since v1-alpha10
*/
private var inputStream: InputFileStream? = null
/**
* Contains the Java [OutputStream]
* for this [Stream] instance.
*
* @since v1-alpha10
*/
private var outputStream: OutputFileStream? = null
// -----> Closure
/**
@ -233,7 +210,7 @@ abstract class Stream(
* @since v1-alpha10
*/
@Throws(IOAccessException::class)
fun writeString(string: String): Stream = writeBytes(string.toByteArray())
fun writeString(string: String): Stream = writeBytes(string.encodeToByteArray())
/**
* Writes (or rather: appends)
@ -245,7 +222,7 @@ abstract class Stream(
* @since v1-alpha10
*/
@Throws(IOAccessException::class)
fun write(value: Any): Stream = writeBytes(value.toString().toByteArray())
fun write(value: Any): Stream = writeBytes(value.toString().encodeToByteArray())
/**
* Flushes all currently
@ -394,7 +371,6 @@ abstract class Stream(
* 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
* @throws IOAccessException on IO error
* @since v1-alpha10
@ -406,14 +382,7 @@ abstract class Stream(
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()
}
platform.startWatchingThread()
return this
}
@ -474,7 +443,7 @@ abstract class Stream(
*
* Make sure to call this method
* before returning from
* [readBytes], [readNBytes]
* [readNextByte], [readNBytes]
* and [readRemainingBytes].
*
* @param byte [Byte] to pipe
@ -494,7 +463,7 @@ abstract class Stream(
*
* Make sure to call this method
* before returning from
* [readBytes], [readNBytes]
* [readNextByte], [readNBytes]
* and [readRemainingBytes].
*
* @param bytes [ByteArray] to pipe
@ -640,36 +609,6 @@ abstract class Stream(
}
// -----> Java interoperability
/**
* Returns this stream as
* a Java [InputStream].
*
* @since v1-alpha10
*/
@NonKotlinContact
fun toInputStream(): InputStream {
if (inputStream == null)
inputStream = InputFileStream(this)
return inputStream!!
}
/**
* Returns this stream as
* a Java [OutputStream].
*
* @since v1-alpha10
*/
@NonKotlinContact
fun toOutputStream(): OutputStream {
if (outputStream == null)
outputStream = OutputFileStream(this)
return outputStream!!
}
// -----> Inner classes
/**
* Represents the mode in which
@ -702,62 +641,4 @@ abstract class Stream(
*/
READ_WRITE,
}
/**
* An implementation of Java
* [InputStream]s for [Stream]s.
*
* @constructor Initializes this stream
* @param stream [Stream] to use
* @throws IOException on IO error
* @since v1-alpha10
*/
class InputFileStream
@NonKotlinContact
internal constructor(val stream: Stream)
: InputStream() {
/**
* Reads the next byte.
*
* @return byte read
* @throws IOException on IO error
* @since v1-alpha10
*/
@Throws(IOException::class)
override fun read(): Int = try {
stream.readNextByte()?.toInt() ?: -1
} catch (exception: IOAccessException) {
throw IOException("Failed reading the next byte", exception)
}
}
/**
* An implementation of Java
* [OutputStream]s for [Stream]s.
*
* @constructor Initializes this stream
* @param stream [Stream] to use
* @since v1-alpha10
*/
@NonKotlinContact
class OutputFileStream
@NonKotlinContact
internal constructor(val stream: Stream)
: OutputStream() {
/**
* Writes (or rather: appends) a byte.
*
* @param byte byte to append
* @throws IOException on IO error
* @since v1-alpha10
*/
@Throws(IOException::class)
override fun write(byte: Int) {
try {
stream.writeByte(byte.toByte())
} catch (exception: IOAccessException) {
throw IOException("Failed writing the next byte", exception)
}
}
}
}

View file

@ -0,0 +1,83 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU General Public License v3.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.platform
import de.staropensource.engine.base.implementable.stream.ReadStream
import de.staropensource.engine.base.implementable.stream.Stream
import de.staropensource.engine.base.implementable.stream.WriteStream
/**
* Platform-specific implementation of [Stream].
*
* @constructor Initializes this platform implementation
* @param stream [Stream] instance
* @since v1-alpha10
*/
abstract class StreamPlatform(
val stream: Stream
) {
/**
* Starts a watching thread for the specified stream.
*
* @param stream [Stream] instance
* @since v1-alpha10
*/
abstract fun startWatchingThread()
}
/**
* Returns a [StreamPlatform] implementation
* for the supplied [Stream] instance.
*
* @param stream [Stream] instance
* @return matching [StreamPlatform] instance
* @since v1-alpha10
*/
internal expect fun streamPlatform(stream: Stream): StreamPlatform
/**
* Returns a [ReadStream] representing
* the standard input of the current
* process.
*
* @return [ReadStream] instance representing the standard input
* @since v1-alpha10
*/
internal expect fun streamStandardInput(): ReadStream
/**
* Returns a [WriteStream] representing
* the standard output of the current
* process.
*
* @return [WriteStream] instance representing the standard output
* @since v1-alpha10
*/
internal expect fun streamStandardOutput(): WriteStream
/**
* Returns a [WriteStream] representing
* the standard error of the current
* process.
*
* @return [WriteStream] instance representing the standard error
* @since v1-alpha10
*/
internal expect fun streamStandardError(): WriteStream

View file

@ -0,0 +1,26 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU General Public License v3.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* Platform-specific implementations
* and helper classes.
*
* @since v1-alpha10
*/
package de.staropensource.engine.base.platform

View file

@ -19,11 +19,9 @@
package de.staropensource.engine.base.utility
import java.math.RoundingMode
import java.text.DecimalFormat
import java.text.DecimalFormatSymbols
import java.util.Locale
import kotlin.jvm.JvmStatic
import kotlin.math.round
import kotlin.math.roundToLong
/**
* Converts between various data size units.
@ -152,11 +150,7 @@ data class DataSize(
* @return modified [Double]
* @since v1-alpha10
*/
fun formatTo(number: Double): Double {
val decimalFormat = DecimalFormat("#.####", DecimalFormatSymbols(Locale.ROOT))
decimalFormat.roundingMode = RoundingMode.HALF_UP
return decimalFormat.format(number).toDouble()
}
fun formatTo(number: Double): Double = round(number.times(1000)).div(1000)
/**
* Performs miscellaneous operations
@ -167,11 +161,7 @@ data class DataSize(
* @return modified [Double]
* @since v1-alpha10
*/
fun formatOf(number: Double): ULong {
val decimalFormat = DecimalFormat("#", DecimalFormatSymbols(Locale.ROOT))
decimalFormat.roundingMode = RoundingMode.HALF_UP
return decimalFormat.format(number).toULong()
}
fun formatOf(number: Double): ULong = number.roundToLong().toULong()
}

View file

@ -0,0 +1,146 @@
/*
* STAROPENSOURCE ENGINE SOURCE FILE
* Copyright (c) 2024 The StarOpenSource Engine Authors
* Licensed under the GNU General Public License v3.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.staropensource.engine.base.platform
import de.staropensource.engine.base.Engine.Companion.logger
import de.staropensource.engine.base.annotation.NonKotlinContact
import de.staropensource.engine.base.exception.io.IOAccessException
import de.staropensource.engine.base.implementable.stream.ReadStream
import de.staropensource.engine.base.implementable.stream.Stream
import de.staropensource.engine.base.implementable.stream.WriteStream
import de.staropensource.engine.base.implementation.stream.JavaReadStream
import de.staropensource.engine.base.implementation.stream.JavaWriteStream
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
/**
* Java implementation of [StreamPlatform].
*
* @constructor Initializes this platform implementation
* @param stream [Stream] instance
* @since v1-alpha10
*/
class StreamPlatformImpl(stream: Stream) : StreamPlatform(stream) {
override fun startWatchingThread() {
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 (!stream.closed && stream.watching)
stream.skipNextByte()
}
}
}
// -----> Actual methods
actual fun streamPlatform(stream: Stream): StreamPlatform = stream.platformData.getOrPut("platform") { StreamPlatformImpl(stream) } as StreamPlatform
actual fun streamStandardInput(): ReadStream = object : JavaReadStream(System.`in`) {
override fun close() = Unit
override fun closeStream() = Unit
}
actual fun streamStandardOutput(): WriteStream = object : JavaWriteStream(System.out) {
override fun close() = Unit
override fun closeStream() = Unit
}
actual fun streamStandardError(): WriteStream = object : JavaWriteStream(System.err) {
override fun close() = Unit
override fun closeStream() = Unit
}
// -----> Extension methods
/**
* Returns this stream as
* a Java [InputStream].
*
* @since v1-alpha10
*/
fun Stream.getJavaInputStream(): InputStream = platformData.getOrPut("inputStream") { InputFileStream(this) } as InputStream
/**
* Returns this stream as
* a Java [OutputStream].
*
* @since v1-alpha10
*/
fun Stream.getJavaOutputStream(): OutputStream = platformData.getOrPut("outputStream") { OutputFileStream(this) } as OutputStream
// ----> Helper classes
/**
* An implementation of Java
* [InputStream]s for [Stream]s.
*
* @constructor Initializes this stream
* @param stream [Stream] to use
* @throws IOException on IO error
* @since v1-alpha10
*/
private class InputFileStream
@NonKotlinContact
constructor(val stream: Stream)
: InputStream() {
/**
* Reads the next byte.
*
* @return byte read
* @throws IOException on IO error
* @since v1-alpha10
*/
@Throws(IOException::class)
override fun read(): Int = try {
stream.readNextByte()?.toInt() ?: -1
} catch (exception: IOAccessException) {
throw IOException("Failed reading the next byte", exception)
}
}
/**
* An implementation of Java
* [OutputStream]s for [Stream]s.
*
* @constructor Initializes this stream
* @param stream [Stream] to use
* @since v1-alpha10
*/
@NonKotlinContact
private class OutputFileStream
@NonKotlinContact
constructor(val stream: Stream)
: OutputStream() {
/**
* Writes (or rather: appends) a byte.
*
* @param byte byte to append
* @throws IOException on IO error
* @since v1-alpha10
*/
@Throws(IOException::class)
override fun write(byte: Int) {
try {
stream.writeByte(byte.toByte())
} catch (exception: IOAccessException) {
throw IOException("Failed writing the next byte", exception)
}
}
}

View file

@ -251,7 +251,7 @@ allprojects {
// -> Copy task
tasks.register("copyGitProperties") {
dependsOn(tasks.generateGitProperties)
inputs.file("${this@allprojects.projectDir}/build/resources/main/git.properties")
inputs.file("${this@allprojects.projectDir}/build/resources/commonMain/git.properties")
doLast {
if (rootProject == this@allprojects)
@ -259,7 +259,7 @@ allprojects {
file(inputs.files.first())
.copyTo(
file("${this@allprojects.projectDir}/src/main/resources/sosengine-${this@allprojects.name.replace(":", "-")}-git.properties"),
file("${this@allprojects.projectDir}/src/commonMain/resources/sosengine-${this@allprojects.name.replace(":", "-")}-git.properties"),
overwrite = true
)
}
@ -279,7 +279,7 @@ allprojects {
file(inputs.files.first())
.copyTo(
file("${this@allprojects.projectDir}/src/main/resources/sosengine-${this@allprojects.name.replace(":", "-")}-gradle.properties"),
file("${this@allprojects.projectDir}/src/commonMain/resources/sosengine-${this@allprojects.name.replace(":", "-")}-gradle.properties"),
overwrite = true
)
}