Breaking Down korge-core into Different Modules #2088
Replies: 8 comments 6 replies
-
I'm fine with it. Before splitting
That's already supported: fun Deflate(windowBits: Int): CompressionMethod
class GZIP : CompressionMethod
suspend fun CompressionMethod.uncompress(i: AsyncInputStream, o: AsyncOutputStream): Unit And to use synchronously if the source and destination is synchronous in the end: fun <T : Any> runBlockingNoSuspensions(callback: suspend () -> T): T |
Beta Was this translation helpful? Give feedback.
-
Ok, I will try my best to contribute there.
Sorry, I missed that. Thanks for pointing it out. I think By the way, I was checking and found a few things missing for my scenario:
Here is an example of Java code that I'm trying to achieve in Kotlin using val stream = GZIPInputStream(FileInputStream(file)) // InputStream
stream.mark
stream.reset
stream.skip
val inputStreamReader = InputStreamReader(input, Charset.forName(charsetName))
inputStreamReader.read(charArray: CharArray, offset: Int, len: Int)
inputStreamReader.mark
inputStreamReader.reset
inputStreamReader.skip I've also made modifications to internal class CharReaderSyncStream(
private val stream: SyncStream,
private val charset: Charset,
private val chunkSize: Int
) : CharReader {
private var temp = ByteArray(chunkSize)
private val buffer = ByteArrayDeque()
private var tempStringBuilder = StringBuilder()
private var markedTempStringBuilder: StringBuilder? = null
private var currentState: ReaderState = ReaderState(consumedBytes = 0, consumedBuffer = 0, lastBytesRead = 0)
private var markedState: ReaderState? = null
override fun clone(): CharReader = CharReaderFromSyncStream(stream.clone(), charset, chunkSize)
init {
stream.mark(SharedConstants.DefaultBufferSize)
}
private fun bufferUp() {
while (buffer.availableRead < temp.size) {
val readCount = stream.read(temp)
if (readCount <= 0) break
currentState = currentState.copy(
consumedBytes = currentState.consumedBytes + readCount,
lastBytesRead = readCount
)
buffer.write(temp, 0, readCount)
if (currentState.applyMarkedState) {
currentState = currentState.copy(applyMarkedState = false)
if (currentState.consumedBuffer > 0) {
buffer.skip(currentState.consumedBuffer)
}
} else {
currentState = currentState.copy(consumedBuffer = 0)
}
}
}
override fun read(out: StringBuilder, count: Int): Int {
bufferUp()
while (tempStringBuilder.length < count) {
val readCount = buffer.peek(temp)
val consumed = charset.decode(tempStringBuilder, temp, 0, readCount)
if (consumed <= 0) break
currentState = currentState.copy(consumedBuffer = currentState.consumedBuffer + consumed)
buffer.skip(consumed)
}
val slice = tempStringBuilder.substring(0, kotlin.math.min(count, tempStringBuilder.length))
tempStringBuilder = StringBuilder(slice.length).append(tempStringBuilder.substring(slice.length))
out.append(slice)
return slice.length
}
fun mark(readLimit: Int) {
this.markedTempStringBuilder = StringBuilder(tempStringBuilder)
this.markedState = this.currentState
}
fun reset() {
if (this.markedState != null) {
if (this.markedTempStringBuilder != null) {
this.tempStringBuilder = StringBuilder(this.markedTempStringBuilder!!)
this.markedTempStringBuilder = null
}
buffer.clear()
temp = ByteArray(chunkSize)
val skipedBytes = this.markedState!!.consumedBytes - this.markedState!!.lastBytesRead
this.currentState = this.markedState!!.copy(consumedBytes = skipedBytes, applyMarkedState = true)
stream.reset()
stream.mark(SharedConstants.DefaultBufferSize)
if (skipedBytes > 0) {
stream.skip(skipedBytes)
}
this.markedState = null
}
}
fun skip(count: Int) {
this.read(count)
}
}
private data class ReaderState(
val consumedBytes: Int,
val consumedBuffer: Int,
val lastBytesRead: Int,
val applyMarkedState: Boolean = false
) Lastly, I've identified some issues in I genuinely appreciate all your hard work on this. It has been tremendously helpful for me, and I hope the broader community will also benefit from these improvements. I apologize if I have initiated several discussions here. Thank you once again for your understanding and assistance. |
Beta Was this translation helpful? Give feedback.
-
Why do you need it? I mean, can't you just duplicate the AsyncStrean to emulate a mark? |
Beta Was this translation helpful? Give feedback.
-
It works like that, because I/O in korio is all asynchronous. There is a separate API for sync I/O but the point on korio is to also work on JS where only async I/O is typically available and also make it difficult to have bottle necks related to I/O. Typically when reading binary stuff, you read asynchronously the header, and with the header, you get the size of the dynamical header information you need and read a full block asynchronously, then you process that block synchronously having that in memory for performance sake. |
Beta Was this translation helpful? Give feedback.
-
What's your scenario for an |
Beta Was this translation helpful? Give feedback.
-
Yeah, because Char is the Kotlin type, not code points. The binary representation of characters change depending on the Charset. I understand in any case that that name can be misleading. But that API is for reading arrays, not strings. If you have ideas on APIs to improve this, feel free to share your thoughts. |
Beta Was this translation helpful? Give feedback.
-
Not implemented AFAIK. Can you put a real example with a case where you would need that mark and reset in a more specific way so I can understand the use-case?
We can make adjustments so it is efficient. But first I want to understand the use-case to know if that's possible to do it with the current API, without adding extra complexity to the implementation. |
Beta Was this translation helpful? Give feedback.
-
@soywiz Why not exclusively concentrate on the In java there is one base class for Stream that is We might require a class similar to |
Beta Was this translation helpful? Give feedback.
-
Hi, I'm testing
korge-core
in one of my Kotlin Multiplatform HML & XML Parser projects ksoup, and it has been really helpful. However, I have a few concerns aboutkorge-core
that could greatly benefit the community. I would like to use charset encoding, streaming API, and gzip compression only from korge-core, but the library is coupled with a lot of extra functionalities.It would be helpful if the library could be divided into modules, such as korge-core (containing only the core without network, compression, or parser code), and create other separate modules like korge-network, korge-compression, korge-parser, etc. This modular approach would make the library more versatile for the Kotlin Multiplatform community.
Additionally, do you have any plans for implementing gzip compression with a streaming API, similar to GZIPInputStream, to decompress files on the fly as only the necessary bytes decompressed?"
Beta Was this translation helpful? Give feedback.
All reactions