-
Notifications
You must be signed in to change notification settings - Fork 64
Support JS IR target #151
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support JS IR target #151
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
/* | ||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. | ||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file. | ||
*/ | ||
|
||
package kotlinx.io | ||
|
||
import kotlinx.io.internal.commonAsUtf8ToByteArray | ||
|
||
internal actual fun String.asUtf8ToByteArray(): ByteArray = commonAsUtf8ToByteArray() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. minor: can't we just use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It ( |
||
|
||
public actual open class IOException actual constructor( | ||
message: String?, | ||
cause: Throwable? | ||
) : Exception(message, cause) { | ||
public actual constructor(message: String?) : this(message, null) | ||
} | ||
|
||
public actual open class EOFException actual constructor(message: String?) : IOException(message) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
/* | ||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. | ||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file. | ||
*/ | ||
|
||
package kotlinx.io | ||
|
||
@OptIn(ExperimentalStdlibApi::class) | ||
public actual interface RawSink : AutoCloseableAlias { | ||
public actual fun write(source: Buffer, byteCount: Long) | ||
|
||
public actual fun flush() | ||
|
||
actual override fun close() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
/* | ||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. | ||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file. | ||
*/ | ||
|
||
package kotlinx.io | ||
|
||
internal actual object SegmentPool { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. question: will JS/Native have pooling some day? If so may be it's better to create an issue for this. Or this will be implemented in scope of #135/different segment types? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It will be considered after #135 (I expect to see the performance improvement on Native w/ enabled pooling, but I didn't measure it yet). |
||
actual val MAX_SIZE: Int = 0 | ||
|
||
actual val byteCount: Int = 0 | ||
|
||
actual fun take(): Segment = Segment() | ||
|
||
actual fun recycle(segment: Segment) { | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
/* | ||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. | ||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file. | ||
*/ | ||
|
||
package kotlinx.io.files | ||
|
||
import kotlinx.io.* | ||
|
||
private val fs: dynamic | ||
get(): dynamic { | ||
return try { | ||
js("require('fs')") | ||
} catch (t: Throwable) { | ||
null | ||
} | ||
} | ||
|
||
private val buffer: dynamic | ||
get(): dynamic { | ||
return try { | ||
js("require('buffer')") | ||
} catch (t: Throwable) { | ||
null | ||
} | ||
} | ||
|
||
public actual class Path internal constructor(private val path: String, | ||
@Suppress("UNUSED_PARAMETER") any: Any?) { | ||
override fun toString(): String = path | ||
} | ||
|
||
public actual fun Path(path: String): Path { | ||
return Path(path, null) | ||
} | ||
|
||
public actual fun Path.source(): Source { | ||
check(fs !== null) { "Module 'fs' was not found" } | ||
return FileSource(this).buffered() | ||
} | ||
|
||
public actual fun Path.sink(): Sink { | ||
check(fs !== null) { "Module 'fs' was not found" } | ||
check(buffer !== null) { "Module 'buffer' was not found" } | ||
return FileSink(this).buffered() | ||
} | ||
|
||
private class FileSource(private val path: Path) : RawSource { | ||
private var buffer: dynamic = null | ||
private var closed = false | ||
private var offset = 0 | ||
|
||
@OptIn(ExperimentalUnsignedTypes::class) | ||
override fun readAtMostTo(sink: Buffer, byteCount: Long): Long { | ||
check(!closed) { "Source is closed." } | ||
if (byteCount == 0L) { | ||
return 0 | ||
} | ||
if (buffer === null) { | ||
buffer = fs.readFileSync(path.toString(), null) | ||
} | ||
val len: Int = buffer.length as Int | ||
if (offset >= len) { | ||
return -1L | ||
} | ||
val bytesToRead = minOf(byteCount, (len - offset)) | ||
for (i in 0 until bytesToRead) { | ||
sink.writeByte(buffer.readInt8(offset++) as Byte) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. minor: we can do bulk copy here: https://nodejs.org/api/buffer.html#bufcopytarget-targetstart-sourcestart-sourceend There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think the issue could be addressed later, after #135 |
||
} | ||
|
||
return bytesToRead | ||
} | ||
|
||
override fun close() { | ||
closed = true | ||
} | ||
} | ||
|
||
private class FileSink(private val path: Path) : RawSink { | ||
private var closed = false | ||
private var append = false | ||
|
||
override fun write(source: Buffer, byteCount: Long) { | ||
check(!closed) { "Sink is closed." } | ||
if (byteCount == 0L) { | ||
return | ||
} | ||
|
||
var remainingBytes = minOf(byteCount, source.size) | ||
while (remainingBytes > 0) { | ||
val head = source.head!! | ||
val segmentBytes = head.limit - head.pos | ||
val buf = buffer.Buffer.allocUnsafe(segmentBytes) | ||
buf.fill(head.data, head.pos, segmentBytes) | ||
if (append) { | ||
fs.appendFileSync(path.toString(), buf) | ||
} else { | ||
fs.writeFileSync(path.toString(), buf) | ||
append = true | ||
} | ||
|
||
source.skip(segmentBytes.toLong()) | ||
remainingBytes -= segmentBytes | ||
} | ||
} | ||
|
||
override fun flush() = Unit | ||
|
||
override fun close() { | ||
closed = true | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/* | ||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. | ||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file. | ||
*/ | ||
|
||
package kotlinx.io | ||
|
||
import kotlin.random.Random | ||
import kotlin.random.nextULong | ||
|
||
private val os: dynamic | ||
get(): dynamic { | ||
return try { | ||
js("require('os')") | ||
} catch (t: Throwable) { | ||
null | ||
} | ||
} | ||
|
||
private val fs: dynamic | ||
get(): dynamic { | ||
return try { | ||
js("require('fs')") | ||
} catch (t: Throwable) { | ||
null | ||
} | ||
} | ||
|
||
private val nodePath: dynamic | ||
get(): dynamic { | ||
return try { | ||
js("require('path')") | ||
} catch (t: Throwable) { | ||
null | ||
} | ||
} | ||
|
||
actual fun createTempFile(): String { | ||
while (true) { | ||
val tmpdir = os.tmpdir() | ||
val filename = Random.nextULong().toString() | ||
val fullpath = "$tmpdir${nodePath.sep}$filename.txt" | ||
|
||
if (fs.existsSync(fullpath) as Boolean) { | ||
continue | ||
} | ||
return fullpath | ||
} | ||
} | ||
|
||
actual fun deleteFile(path: String) { | ||
if (!fs.existsSync(path) as Boolean) { | ||
throw IOException("File does not exist: $path") | ||
} | ||
fs.rmSync(path) | ||
} |
Uh oh!
There was an error while loading. Please reload this page.