more KMP targets
This commit is contained in:
parent
3c33eb3bd9
commit
e9082af4de
@ -17,6 +17,7 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
|
jvmToolchain(17)
|
||||||
jvm {
|
jvm {
|
||||||
compilations.all {
|
compilations.all {
|
||||||
kotlinOptions.jvmTarget = "1.8"
|
kotlinOptions.jvmTarget = "1.8"
|
||||||
@ -48,15 +49,32 @@ kotlin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val hostOs = System.getProperty("os.name")
|
// val hostOs = System.getProperty("os.name")
|
||||||
val isMingwX64 = hostOs.startsWith("Windows")
|
// val isMingwX64 = hostOs.startsWith("Windows")
|
||||||
val nativeTarget = when {
|
// val nativeTarget = when {
|
||||||
hostOs == "Mac OS X" -> macosX64("native")
|
// hostOs == "Mac OS X" -> macosX64("native")
|
||||||
hostOs == "Linux" -> linuxX64("native")
|
// hostOs == "Linux" -> linuxX64("native")
|
||||||
isMingwX64 -> mingwX64("native")
|
// isMingwX64 -> mingwX64("native")
|
||||||
else -> throw GradleException("Host OS is not supported in Kotlin/Native.")
|
// else -> throw GradleException("Host OS is not supported in Kotlin/Native.")
|
||||||
|
// }
|
||||||
|
|
||||||
|
linuxX64("native") {
|
||||||
|
binaries.staticLib {
|
||||||
|
baseName = "mp_bintools"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wasmJs {
|
||||||
|
browser()
|
||||||
|
binaries.executable()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
mingwX64() {
|
||||||
|
binaries.staticLib {
|
||||||
|
baseName = "mp_bintools"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
all {
|
all {
|
||||||
@ -66,29 +84,35 @@ kotlin {
|
|||||||
}
|
}
|
||||||
val commonMain by getting {
|
val commonMain by getting {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
|
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0")
|
||||||
// this is actually a bug: we need only the core, but bare core causes strange errors
|
// this is actually a bug: we need only the core, but bare core causes strange errors
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0")
|
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
|
||||||
// api("net.sergeych:mp_stools:[1.3.3,)")
|
// api("net.sergeych:mp_stools:[1.3.3,)")
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0")
|
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.5.0")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val commonTest by getting {
|
val commonTest by getting {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(kotlin("test"))
|
implementation(kotlin("test"))
|
||||||
implementation("net.sergeych:mp_stools:1.4.1")
|
implementation("net.sergeych:mp_stools:1.4.4-SNAPSHOT")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val jvmMain by getting
|
val jvmMain by getting
|
||||||
val jvmTest by getting
|
val jvmTest by getting
|
||||||
val jsMain by getting {
|
val jsMain by getting {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("net.sergeych:mp_stools:1.4.3")
|
implementation("net.sergeych:mp_stools:1.4.4-SNAPSHOT")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val jsTest by getting
|
val jsTest by getting
|
||||||
val nativeMain by getting
|
val nativeMain by getting
|
||||||
val nativeTest by getting
|
val nativeTest by getting
|
||||||
|
val wasmJsMain by getting {
|
||||||
|
dependencies {
|
||||||
|
implementation("net.sergeych:mp_stools:1.4.4-SNAPSHOT")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val wasmJsTest by getting
|
||||||
}
|
}
|
||||||
|
|
||||||
publishing {
|
publishing {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package net.sergeych.synctools
|
package net.sergeych.synctools
|
||||||
|
|
||||||
import net.sergeych.tools.AtomicCounter
|
|
||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
package net.sergeych.bintools
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create per-platform default named storage.
|
||||||
|
*
|
||||||
|
* - In the browser, it uses the `Window.localStorage` prefixing items
|
||||||
|
* by a string containing the [name]
|
||||||
|
*
|
||||||
|
* - In the JVM environment it uses folder-based storage on the file system. The name
|
||||||
|
* is considered to be a folder name (the whole path which will be automatically created)
|
||||||
|
* using the following rules:
|
||||||
|
* - when the name starts with slash (`/`) it is treated as an absolute path to a folder
|
||||||
|
* - when the name contains slash, it is considered to be a relative folder to the
|
||||||
|
* `User.home` directory, like "`~/`" on unix systems.
|
||||||
|
* - otherwise, the folder will be created in "`~/.local_storage`" parent directory
|
||||||
|
* (which also will be created if needed).
|
||||||
|
*
|
||||||
|
* - For the native platorms it is not yet implemented (but will be soon).
|
||||||
|
*
|
||||||
|
* See [DataKVStorage] and [DataProvider] to implement a KVStorage on filesystems and like,
|
||||||
|
* and `FileDataProvider` class on JVM target.
|
||||||
|
*/
|
||||||
|
actual fun defaultNamedStorage(name: String): KVStorage {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package net.sergeych.synctools
|
||||||
|
|
||||||
|
import kotlinx.atomicfu.locks.ReentrantLock
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Native implementation uses `ReentrantLock`]
|
||||||
|
*/
|
||||||
|
actual fun ProtectedOp(): ProtectedOpImplementation = object : ProtectedOpImplementation {
|
||||||
|
private val access = ReentrantLock()
|
||||||
|
override fun lock() {
|
||||||
|
access.lock()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun unlock() {
|
||||||
|
access.unlock()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package net.sergeych.synctools
|
||||||
|
|
||||||
|
import kotlinx.coroutines.TimeoutCancellationException
|
||||||
|
import kotlinx.coroutines.channels.Channel
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import kotlinx.coroutines.withTimeout
|
||||||
|
|
||||||
|
@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING")
|
||||||
|
actual class WaitHandle {
|
||||||
|
private val channel = Channel<Unit>()
|
||||||
|
actual fun await(milliseconds: Long): Boolean {
|
||||||
|
return runBlocking {
|
||||||
|
try {
|
||||||
|
if( milliseconds > 0) {
|
||||||
|
withTimeout(milliseconds) {
|
||||||
|
channel.receive()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
channel.receive()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(_: TimeoutCancellationException) {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun wakeUp() {
|
||||||
|
runBlocking { channel.send(Unit) }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
package net.sergeych.bintools
|
||||||
|
|
||||||
|
import kotlinx.browser.localStorage
|
||||||
|
import net.sergeych.mp_tools.decodeBase64Compact
|
||||||
|
import net.sergeych.mp_tools.encodeToBase64Compact
|
||||||
|
import org.w3c.dom.Storage
|
||||||
|
import org.w3c.dom.set
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create per-platform default named storage.
|
||||||
|
*
|
||||||
|
* - In the browser, it uses the `Window.localStorage` prefixing items
|
||||||
|
* by a string containing the [name]
|
||||||
|
*
|
||||||
|
* - In the JVM environment it uses folder-based storage on the file system. The name
|
||||||
|
* is considered to be a folder name (the whole path which will be automatically created)
|
||||||
|
* using the following rules:
|
||||||
|
* - when the name starts with slash (`/`) it is treated as an absolute path to a folder
|
||||||
|
* - when the name contains slash, it is considered to be a relative folder to the
|
||||||
|
* `User.home` directory, like "`~/`" on unix systems.
|
||||||
|
* - otherwise, the folder will be created in "`~/.local_storage`" parent directory
|
||||||
|
* (which also will be created if needed).
|
||||||
|
*
|
||||||
|
* - For the native platorms it is not yet implemented (but will be soon).
|
||||||
|
*
|
||||||
|
* See [DataKVStorage] and [DataProvider] to implement a KVStorage on filesystems and like,
|
||||||
|
* and `FileDataProvider` class on JVM target.
|
||||||
|
*/
|
||||||
|
actual fun defaultNamedStorage(name: String): KVStorage = BrowserKVStorage(name, localStorage)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default KV storage in browser. Use if with `localStorage` or `sessionStorage`. It uses
|
||||||
|
* prefix for storage values not to collide with other data, beware of it.
|
||||||
|
*/
|
||||||
|
class BrowserKVStorage(keyPrefix: String, private val bst: Storage) : KVStorage {
|
||||||
|
|
||||||
|
private val prefix = "$keyPrefix:"
|
||||||
|
fun k(key: String) = "$prefix$key"
|
||||||
|
override fun get(key: String): ByteArray? {
|
||||||
|
return bst.getItem(k(key))?.decodeBase64Compact()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun set(key: String, value: ByteArray?) {
|
||||||
|
val corrected = k(key)
|
||||||
|
if (value == null)
|
||||||
|
bst.removeItem(corrected)
|
||||||
|
else
|
||||||
|
bst.set(corrected, value.encodeToBase64Compact())
|
||||||
|
}
|
||||||
|
|
||||||
|
override val keys: Set<String>
|
||||||
|
get() {
|
||||||
|
val kk = mutableListOf<String>()
|
||||||
|
for (i in 0 until bst.length) {
|
||||||
|
val k = bst.key(i) ?: break
|
||||||
|
if( k.startsWith(prefix)) {
|
||||||
|
kk += k.substring(prefix.length)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return kk.toSet()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package net.sergeych.synctools
|
||||||
|
|
||||||
|
import kotlinx.atomicfu.locks.ReentrantLock
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the platform-depended implementation of a mutex. It does nothing in the
|
||||||
|
* browser and use appropriate mechanics on JVM and native targets. See
|
||||||
|
* [ProtectedOpImplementation.invoke], [ProtectedOpImplementation.withLock]
|
||||||
|
* ```kotlin
|
||||||
|
* val op = ProtectedOp()
|
||||||
|
* //...
|
||||||
|
* op {
|
||||||
|
* // mutually exclusive execution
|
||||||
|
* println("sequential execution here")
|
||||||
|
* }
|
||||||
|
* ~~~
|
||||||
|
*/
|
||||||
|
actual fun ProtectedOp(): ProtectedOpImplementation = object: ProtectedOpImplementation {
|
||||||
|
val rlock = ReentrantLock()
|
||||||
|
override fun lock() {
|
||||||
|
rlock.lock()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun unlock() {
|
||||||
|
rlock.unlock()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package net.sergeych.synctools
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Platform-independent interface to thread wait/notify. Does nothing in JS/browser,
|
||||||
|
* and uses appropriate mechanics on other platforms.
|
||||||
|
*
|
||||||
|
* Wasm is effictively songle threaded at the moment
|
||||||
|
*/
|
||||||
|
@Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING")
|
||||||
|
actual class WaitHandle {
|
||||||
|
actual fun await(milliseconds: Long): Boolean {
|
||||||
|
// in JS we can't wait: no threads
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
actual fun wakeUp() {
|
||||||
|
// in JS we can't wait: no threads
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user