Skip to content

Commit 9db0e5f

Browse files
authored
Commonize js & wasmJs code (#49)
1 parent e7fc209 commit 9db0e5f

File tree

9 files changed

+199
-164
lines changed

9 files changed

+199
-164
lines changed

library/crypto-rand/build.gradle.kts

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -44,23 +44,35 @@ kmpConfiguration {
4444

4545
kotlin {
4646
with(sourceSets) {
47-
val linuxMain = findByName("linuxMain")
48-
val androidNativeMain = findByName("androidNativeMain")
49-
50-
if (linuxMain != null || androidNativeMain != null) {
51-
val linuxAndroidMain = maybeCreate("linuxAndroidMain").apply {
52-
dependsOn(getByName("unixMain"))
53-
}
54-
val linuxAndroidTest = maybeCreate("linuxAndroidTest").apply {
55-
dependsOn(getByName("unixTest"))
56-
}
57-
58-
linuxMain?.apply { dependsOn(linuxAndroidMain) }
59-
findByName("linuxTest")?.apply { dependsOn(linuxAndroidTest) }
47+
val sets = arrayOf("js", "wasmJs").mapNotNull { name ->
48+
val main = findByName("${name}Main") ?: return@mapNotNull null
49+
main to getByName("${name}Test")
50+
}
51+
if (sets.isEmpty()) return@kotlin
52+
val main = maybeCreate("jsWasmJsMain").apply {
53+
dependsOn(getByName("nonJvmMain"))
54+
}
55+
val test = maybeCreate("jsWasmJsTest").apply {
56+
dependsOn(getByName("nonJvmTest"))
57+
}
58+
sets.forEach { (m, t) -> m.dependsOn(main); t.dependsOn(test) }
59+
}
60+
}
6061

61-
androidNativeMain?.apply { dependsOn(linuxAndroidMain) }
62-
findByName("androidNativeTest")?.apply { dependsOn(linuxAndroidTest) }
62+
kotlin {
63+
with(sourceSets) {
64+
val sets = arrayOf("linux", "androidNative").mapNotNull { name ->
65+
val main = findByName("${name}Main") ?: return@mapNotNull null
66+
main to getByName("${name}Test")
67+
}
68+
if (sets.isEmpty()) return@kotlin
69+
val main = maybeCreate("linuxAndroidMain").apply {
70+
dependsOn(getByName("unixMain"))
71+
}
72+
val test = maybeCreate("linuxAndroidTest").apply {
73+
dependsOn(getByName("unixTest"))
6374
}
75+
sets.forEach { (m, t) -> m.dependsOn(main); t.dependsOn(test) }
6476
}
6577
}
6678

library/crypto-rand/src/jsMain/kotlin/org/kotlincrypto/random/internal/JsPlatform.kt

Lines changed: 0 additions & 105 deletions
This file was deleted.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright (c) 2025 KotlinCrypto
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
**/
16+
package org.kotlincrypto.random.internal.js
17+
18+
internal actual val IS_NODE_JS: Boolean by lazy { isNodeJs() }
19+
20+
internal actual fun jsCryptoBrowser(): JsCrypto = js(CODE_JS_CRYPTO_BROWSER)
21+
internal actual fun jsCryptoNode(): JsCrypto = js(CODE_JS_CRYPTO_NODE)
22+
23+
private fun isNodeJs(): Boolean = js(CODE_IS_NODE_JS)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* Copyright (c) 2025 KotlinCrypto
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
**/
16+
package org.kotlincrypto.random.internal.js
17+
18+
internal actual fun jsUint8ArrayGet(array: JsUint8Array, index: Int): Byte = js("array[index]")
19+
internal actual fun jsUint8ArraySet(array: JsUint8Array, index: Int, value: Byte) { js("array[index] = value") }
Lines changed: 12 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -13,65 +13,33 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
**/
16-
@file:Suppress("ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT", "KotlinRedundantDiagnosticSuppress", "UNUSED")
17-
1816
package org.kotlincrypto.random.internal
1917

2018
import org.kotlincrypto.random.RandomnessProcurementException
19+
import org.kotlincrypto.random.internal.js.IS_NODE_JS
20+
import org.kotlincrypto.random.internal.js.JsCrypto
21+
import org.kotlincrypto.random.internal.js.JsUint8Array
22+
import org.kotlincrypto.random.internal.js.get
23+
import org.kotlincrypto.random.internal.js.jsCryptoBrowser
24+
import org.kotlincrypto.random.internal.js.jsCryptoNode
25+
import org.kotlincrypto.random.internal.js.set
2126

2227
private const val BUFFER_SIZE = 1024 * 8
2328

24-
private external interface Crypto: JsAny {
25-
// Browser
26-
fun getRandomValues(array: Uint8Array)
27-
// Node.js
28-
fun randomFillSync(buf: Uint8Array)
29-
}
30-
31-
private open external class Uint8Array(length: Int) {
32-
fun subarray(start: Int, end: Int): Uint8Array
33-
}
34-
35-
@Suppress("UNUSED_PARAMETER")
36-
private fun uint8ArrayGet(obj: Uint8Array, index: Int): Byte = js("obj[index]")
37-
@Suppress("NOTHING_TO_INLINE")
38-
private inline operator fun Uint8Array.get(index: Int): Byte = uint8ArrayGet(this, index)
39-
40-
@Suppress("UNUSED_PARAMETER")
41-
private fun uint8ArraySet(obj: Uint8Array, index: Int, value: Byte) { js("obj[index] = value") }
42-
@Suppress("NOTHING_TO_INLINE")
43-
private inline operator fun Uint8Array.set(index: Int, value: Byte) { uint8ArraySet(this, index, value) }
44-
45-
private fun isNodeJs(): Boolean = js(
46-
"""
47-
(typeof process !== 'undefined'
48-
&& process.versions != null
49-
&& process.versions.node != null) ||
50-
(typeof window !== 'undefined'
51-
&& typeof window.process !== 'undefined'
52-
&& window.process.versions != null
53-
&& window.process.versions.node != null)
54-
"""
55-
)
56-
57-
private fun cryptoNode(): Crypto = js("eval('require')('crypto')")
58-
private fun cryptoBrowser(): Crypto = js("(window ? (window.crypto ? window.crypto : window.msCrypto) : self.crypto)")
59-
60-
private val IS_NODE_JS: Boolean by lazy { isNodeJs() }
61-
private val CRYPTO: Crypto by lazy { if (IS_NODE_JS) cryptoNode() else cryptoBrowser() }
29+
private val JS_CRYPTO: JsCrypto by lazy { if (IS_NODE_JS) jsCryptoNode() else jsCryptoBrowser() }
6230

63-
//@Throws(RandomnessProcurementException::class)
31+
@Throws(RandomnessProcurementException::class)
6432
internal actual fun ByteArray.cryptoRandFill() {
6533
try {
66-
val jsCryptoFill = if (IS_NODE_JS) CRYPTO::randomFillSync else CRYPTO::getRandomValues
34+
val jsCryptoFill = if (IS_NODE_JS) JS_CRYPTO::randomFillSync else JS_CRYPTO::getRandomValues
6735

6836
// Cannot simply use the ByteArray when calling the supplied Crypto function.
6937
// Must utilize Uint8Array and then copy over results (See Issue #8). Also,
7038
// by chunking in a size less than 65536, it avoids hitting the ceiling imposed
7139
// on JS Browser (See issue #9).
7240
if (size <= BUFFER_SIZE) {
7341
// 1 shot it
74-
val buf = Uint8Array(size)
42+
val buf = JsUint8Array(size)
7543
jsCryptoFill(buf)
7644
for (i in indices) {
7745
this[i] = buf[i]
@@ -80,7 +48,7 @@ internal actual fun ByteArray.cryptoRandFill() {
8048
return
8149
}
8250

83-
val buf = Uint8Array(BUFFER_SIZE)
51+
val buf = JsUint8Array(BUFFER_SIZE)
8452

8553
var needed = size
8654
var pos = 0
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright (c) 2025 KotlinCrypto
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
**/
16+
package org.kotlincrypto.random.internal.js
17+
18+
internal external interface JsCrypto {
19+
// Browser
20+
fun getRandomValues(array: JsUint8Array)
21+
// Node.js
22+
fun randomFillSync(buf: JsUint8Array)
23+
}
24+
25+
internal const val CODE_IS_NODE_JS: String =
26+
"""
27+
(typeof process !== 'undefined'
28+
&& process.versions != null
29+
&& process.versions.node != null) ||
30+
(typeof window !== 'undefined'
31+
&& typeof window.process !== 'undefined'
32+
&& window.process.versions != null
33+
&& window.process.versions.node != null)
34+
"""
35+
36+
internal const val CODE_JS_CRYPTO_BROWSER: String =
37+
"(window ? (window.crypto ? window.crypto : window.msCrypto) : self.crypto)"
38+
39+
internal const val CODE_JS_CRYPTO_NODE: String =
40+
"eval('require')('crypto')"
41+
42+
internal expect val IS_NODE_JS: Boolean
43+
44+
internal expect fun jsCryptoBrowser(): JsCrypto
45+
internal expect fun jsCryptoNode(): JsCrypto
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Copyright (c) 2025 KotlinCrypto
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
**/
16+
@file:Suppress("NOTHING_TO_INLINE", "UNUSED")
17+
18+
package org.kotlincrypto.random.internal.js
19+
20+
import kotlin.js.JsName
21+
22+
@JsName("Uint8Array")
23+
internal open external class JsUint8Array(length: Int) {
24+
fun subarray(start: Int, end: Int): JsUint8Array
25+
}
26+
27+
internal inline operator fun JsUint8Array.get(index: Int): Byte = jsUint8ArrayGet(this, index)
28+
internal inline operator fun JsUint8Array.set(index: Int, value: Byte) { jsUint8ArraySet(this, index, value) }
29+
30+
internal expect fun jsUint8ArrayGet(array: JsUint8Array, index: Int): Byte
31+
internal expect fun jsUint8ArraySet(array: JsUint8Array, index: Int, value: Byte)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright (c) 2025 KotlinCrypto
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
**/
16+
package org.kotlincrypto.random.internal.js
17+
18+
internal actual val IS_NODE_JS: Boolean by lazy { isNodeJs() }
19+
20+
internal actual fun jsCryptoBrowser(): JsCrypto = js(CODE_JS_CRYPTO_BROWSER)
21+
internal actual fun jsCryptoNode(): JsCrypto = js(CODE_JS_CRYPTO_NODE)
22+
23+
private fun isNodeJs(): Boolean = js(CODE_IS_NODE_JS)

0 commit comments

Comments
 (0)