Skip to content

Commit 5a50657

Browse files
committed
Added Wasm support (No Wasi for kRPC)
1 parent 81bed3c commit 5a50657

File tree

27 files changed

+384
-70
lines changed

27 files changed

+384
-70
lines changed

build.gradle.kts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,20 @@
44

55
import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion
66
import util.kotlinVersionParsed
7+
import util.libs
78

89
plugins {
910
alias(libs.plugins.serialization) apply false
1011
alias(libs.plugins.kotlinx.rpc) apply false
11-
alias(libs.plugins.atomicfu) apply false
1212
alias(libs.plugins.conventions.kover)
1313
alias(libs.plugins.conventions.gradle.doctor)
1414
alias(libs.plugins.binary.compatibility.validator)
15+
16+
if (libs.versions.atomicfu.get() >= "0.24.0") {
17+
alias(libs.plugins.atomicfu.new)
18+
} else {
19+
alias(libs.plugins.atomicfu.old)
20+
}
1521
}
1622

1723
// useful for dependencies introspection

compiler-plugin/compiler-plugin-backend/src/main/core/kotlinx/rpc/codegen/extension/RPCIrContext.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.ir.types.makeNullable
1616
import org.jetbrains.kotlin.ir.util.functions
1717
import org.jetbrains.kotlin.ir.util.isVararg
1818
import org.jetbrains.kotlin.ir.util.properties
19+
import org.jetbrains.kotlin.platform.isWasm
1920
import org.jetbrains.kotlin.platform.konan.isNative
2021
import org.jetbrains.kotlin.types.Variance
2122

@@ -131,6 +132,10 @@ internal class RPCIrContext(
131132
return pluginContext.platform.isNative()
132133
}
133134

135+
fun isWasmTarget(): Boolean {
136+
return pluginContext.platform.isWasm()
137+
}
138+
134139
val functions = Functions()
135140

136141
inner class Functions {

compiler-plugin/compiler-plugin-backend/src/main/core/kotlinx/rpc/codegen/extension/RPCStubGenerator.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1209,10 +1209,10 @@ internal class RPCStubGenerator(
12091209
}
12101210
}
12111211

1212-
// Associated object annotation works on JS and Native platforms.
1212+
// Associated object annotation works on JS, WASM, and Native platforms.
12131213
// See https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/find-associated-object.html
12141214
private fun addAssociatedObjectAnnotationIfPossible() {
1215-
if (ctx.isJsTarget() || ctx.isNativeTarget()) {
1215+
if (ctx.isJsTarget() || ctx.isNativeTarget() || ctx.isWasmTarget()) {
12161216
addAssociatedObjectAnnotation()
12171217
}
12181218
}

core/build.gradle.kts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
1+
/*
2+
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
import util.applyAtomicfuPlugin
6+
17
/*
28
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
39
*/
410

511
plugins {
612
alias(libs.plugins.conventions.kmp)
7-
alias(libs.plugins.atomicfu)
13+
alias(libs.plugins.kotlinx.rpc)
14+
alias(libs.plugins.serialization)
815
}
916

17+
applyAtomicfuPlugin()
18+
1019
kotlin {
1120
sourceSets {
1221
commonMain {
@@ -24,5 +33,11 @@ kotlin {
2433
implementation(libs.kotlin.js.wrappers)
2534
}
2635
}
36+
37+
wasmJsMain {
38+
dependencies {
39+
implementation(libs.kotlinx.browser)
40+
}
41+
}
2742
}
2843
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
@file:Suppress("detekt.MatchingDeclarationName")
6+
7+
package kotlinx.rpc.internal
8+
9+
import kotlinx.rpc.internal.utils.InternalRPCApi
10+
import kotlin.reflect.KClass
11+
12+
@InternalRPCApi
13+
public actual val KClass<*>.qualifiedClassNameOrNull: String?
14+
get() = toString()
15+
16+
@InternalRPCApi
17+
public actual val KClass<*>.typeName: String?
18+
get() = qualifiedClassNameOrNull
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
@file:Suppress("detekt.MatchingDeclarationName")
6+
7+
package kotlinx.rpc.internal
8+
9+
import kotlinx.rpc.RPC
10+
import kotlinx.rpc.internal.utils.InternalRPCApi
11+
import kotlin.reflect.AssociatedObjectKey
12+
import kotlin.reflect.ExperimentalAssociatedObjects
13+
import kotlin.reflect.KClass
14+
import kotlin.reflect.findAssociatedObject
15+
16+
@InternalRPCApi
17+
@AssociatedObjectKey
18+
@OptIn(ExperimentalAssociatedObjects::class)
19+
@Target(AnnotationTarget.CLASS)
20+
public annotation class WithRPCStubObject(
21+
@Suppress("unused")
22+
val stub: KClass<out RPCStubObject<out RPC>>
23+
)
24+
25+
@OptIn(ExperimentalAssociatedObjects::class)
26+
@InternalRPCApi
27+
public actual fun <R : Any> findRPCStubProvider(kClass: KClass<*>, resultKClass: KClass<R>): R {
28+
val associatedObject = kClass.findAssociatedObject<WithRPCStubObject>()
29+
?: internalError("Unable to find $kClass associated object")
30+
31+
if (resultKClass.isInstance(associatedObject)) {
32+
@Suppress("UNCHECKED_CAST")
33+
return associatedObject as R
34+
}
35+
36+
internalError(
37+
"Located associated object is not of desired type $resultKClass, " +
38+
"instead found $associatedObject of class " +
39+
(associatedObject::class.qualifiedClassNameOrNull ?: associatedObject::class)
40+
)
41+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
@file:Suppress("detekt.MatchingDeclarationName")
6+
7+
package kotlinx.rpc.internal
8+
9+
import kotlinx.rpc.internal.utils.InternalRPCApi
10+
import kotlin.reflect.KClass
11+
12+
@InternalRPCApi
13+
public actual val KClass<*>.qualifiedClassNameOrNull: String?
14+
get() = toString()
15+
16+
@InternalRPCApi
17+
public actual val KClass<*>.typeName: String?
18+
get() = qualifiedClassNameOrNull
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
@file:Suppress("detekt.MatchingDeclarationName")
6+
7+
package kotlinx.rpc.internal
8+
9+
import kotlinx.rpc.RPC
10+
import kotlinx.rpc.internal.utils.InternalRPCApi
11+
import kotlin.reflect.AssociatedObjectKey
12+
import kotlin.reflect.ExperimentalAssociatedObjects
13+
import kotlin.reflect.KClass
14+
import kotlin.reflect.findAssociatedObject
15+
16+
@InternalRPCApi
17+
@AssociatedObjectKey
18+
@OptIn(ExperimentalAssociatedObjects::class)
19+
@Target(AnnotationTarget.CLASS)
20+
public annotation class WithRPCStubObject(
21+
@Suppress("unused")
22+
val stub: KClass<out RPCStubObject<out RPC>>
23+
)
24+
25+
@OptIn(ExperimentalAssociatedObjects::class)
26+
@InternalRPCApi
27+
public actual fun <R : Any> findRPCStubProvider(kClass: KClass<*>, resultKClass: KClass<R>): R {
28+
val associatedObject = kClass.findAssociatedObject<WithRPCStubObject>()
29+
?: internalError("Unable to find $kClass associated object")
30+
31+
if (resultKClass.isInstance(associatedObject)) {
32+
@Suppress("UNCHECKED_CAST")
33+
return associatedObject as R
34+
}
35+
36+
internalError(
37+
"Located associated object is not of desired type $resultKClass, " +
38+
"instead found $associatedObject of class " +
39+
(associatedObject::class.qualifiedClassNameOrNull ?: associatedObject::class)
40+
)
41+
}

gradle-conventions-settings/src/main/kotlin/util/JsTarget.kt

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,50 @@
44

55
package util
66

7-
import org.gradle.api.Project
7+
import org.gradle.api.Action
88
import org.gradle.kotlin.dsl.invoke
9+
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
10+
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
11+
import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl
12+
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsTargetDsl
13+
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget
914
import java.io.File
1015

11-
fun Project.configureJs() {
12-
configureJsTasks()
16+
fun ProjectKotlinConfig.configureJsAndWasmJs() {
17+
configureJsAndWasmJsTasks()
1318

1419
kotlin {
1520
sourceSets {
16-
jsTest {
17-
dependencies {
18-
implementation(npm("puppeteer", "*"))
21+
if (js) {
22+
jsTest {
23+
puppeteer()
24+
}
25+
}
26+
27+
if (wasmJs) {
28+
wasmJsMain {
29+
dependencies {
30+
implementation(libs.kotlinx.browser)
31+
}
32+
}
33+
34+
wasmJsTest {
35+
puppeteer()
1936
}
2037
}
2138
}
2239
}
2340
}
2441

25-
private fun Project.configureJsTasks() {
42+
private fun KotlinSourceSet.puppeteer() {
43+
dependencies {
44+
implementation(npm("puppeteer", "*"))
45+
}
46+
}
47+
48+
private fun ProjectKotlinConfig.configureJsAndWasmJsTasks() {
2649
kotlin {
27-
js(IR) {
50+
jsAnsWasmJs(this@configureJsAndWasmJsTasks) {
2851
nodejs {
2952
testTask {
3053
useMocha {
@@ -33,16 +56,25 @@ private fun Project.configureJsTasks() {
3356
}
3457
}
3558

36-
browser {
59+
(this as KotlinJsIrTarget).whenBrowserConfigured {
3760
testTask {
3861
useKarma {
3962
useChromeHeadless()
4063
useConfigDirectory(File(project.rootProject.projectDir, "karma"))
4164
}
4265
}
4366
}
44-
45-
binaries.library()
4667
}
4768
}
4869
}
70+
71+
@OptIn(ExperimentalWasmDsl::class)
72+
private fun KotlinMultiplatformExtension.jsAnsWasmJs(
73+
config: ProjectKotlinConfig,
74+
configure: Action<KotlinJsTargetDsl>,
75+
) {
76+
listOfNotNull(
77+
if (config.js) js(IR) else null,
78+
if (config.wasmJs) wasmJs() else null,
79+
).forEach { configure(it) }
80+
}

gradle-conventions-settings/src/main/kotlin/util/OptionalProperty.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import org.gradle.api.Project
88
import kotlin.reflect.KProperty
99

1010
class OptionalProperty(private val target: Project) {
11-
operator fun getValue(thisRef: Any, property: KProperty<*>): Boolean {
11+
operator fun getValue(thisRef: Any?, property: KProperty<*>): Boolean {
1212
return getValue("kotlinx.rpc.${property.name}")
1313
}
1414

0 commit comments

Comments
 (0)