diff --git a/base/src/commonMain/kotlin/de/staropensource/engine/base/implementable/PlatformData.kt b/base/src/commonMain/kotlin/de/staropensource/engine/base/implementable/PlatformData.kt
new file mode 100644
index 0000000..833b390
--- /dev/null
+++ b/base/src/commonMain/kotlin/de/staropensource/engine/base/implementable/PlatformData.kt
@@ -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 .
+ */
+
+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
+}
diff --git a/base/src/commonMain/kotlin/de/staropensource/engine/base/implementable/stream/Stream.kt b/base/src/commonMain/kotlin/de/staropensource/engine/base/implementable/stream/Stream.kt
index 137a610..fe27045 100644
--- a/base/src/commonMain/kotlin/de/staropensource/engine/base/implementable/stream/Stream.kt
+++ b/base/src/commonMain/kotlin/de/staropensource/engine/base/implementable/stream/Stream.kt
@@ -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 stdin(3)
* @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 stdout(3)
* @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 stderr(3)
* @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 = mutableMapOf()
+ private val platform: StreamPlatform = streamPlatform(this)
+
/**
* Indicates whether this stream is closed.
*
@@ -133,22 +126,6 @@ abstract class Stream(
*/
val pipes: MutableList = 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)
- }
- }
- }
}
diff --git a/base/src/commonMain/kotlin/de/staropensource/engine/base/platform/StreamPlatform.kt b/base/src/commonMain/kotlin/de/staropensource/engine/base/platform/StreamPlatform.kt
new file mode 100644
index 0000000..bf14e81
--- /dev/null
+++ b/base/src/commonMain/kotlin/de/staropensource/engine/base/platform/StreamPlatform.kt
@@ -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 .
+ */
+
+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
diff --git a/base/src/commonMain/kotlin/de/staropensource/engine/base/platform/package-info.kt b/base/src/commonMain/kotlin/de/staropensource/engine/base/platform/package-info.kt
new file mode 100644
index 0000000..374f989
--- /dev/null
+++ b/base/src/commonMain/kotlin/de/staropensource/engine/base/platform/package-info.kt
@@ -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 .
+ */
+
+/**
+ * Platform-specific implementations
+ * and helper classes.
+ *
+ * @since v1-alpha10
+ */
+package de.staropensource.engine.base.platform
diff --git a/base/src/commonMain/kotlin/de/staropensource/engine/base/utility/DataSize.kt b/base/src/commonMain/kotlin/de/staropensource/engine/base/utility/DataSize.kt
index c24dd52..114915d 100644
--- a/base/src/commonMain/kotlin/de/staropensource/engine/base/utility/DataSize.kt
+++ b/base/src/commonMain/kotlin/de/staropensource/engine/base/utility/DataSize.kt
@@ -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()
}
diff --git a/base/src/jvmMain/kotlin/de/staropensource/engine/base/platform/StreamPlatformImpl.kt b/base/src/jvmMain/kotlin/de/staropensource/engine/base/platform/StreamPlatformImpl.kt
new file mode 100644
index 0000000..cbeb93d
--- /dev/null
+++ b/base/src/jvmMain/kotlin/de/staropensource/engine/base/platform/StreamPlatformImpl.kt
@@ -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 .
+ */
+
+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)
+ }
+ }
+}
diff --git a/build.gradle.kts b/build.gradle.kts
index cb199af..c8a01d0 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -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
)
}