[JSON-AST] Publishing native artifact on bintray
diff --git a/build.gradle b/build.gradle
index 1de27b2..dd26167 100644
--- a/build.gradle
+++ b/build.gradle
@@ -33,13 +33,18 @@
maven { url "https://plugins.gradle.org/m2/" }
maven { url eapChannel }
maven { url serializationRepo }
+ maven { url "https://dl.bintray.com/jetbrains/kotlin-native-dependencies" }
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$compilerVersion"
classpath "org.jetbrains.kotlinx:kotlinx-gradle-serialization-plugin:$serializationPluginVersion"
+ classpath "org.jetbrains.kotlin:kotlin-native-gradle-plugin:${property('konan.version')}"
+
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.2'
- classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3'
+
+ classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.2-SNAPSHOT'
+
classpath "com.github.jengelman.gradle.plugins:shadow:2.0.2"
classpath "me.champeau.gradle:jmh-gradle-plugin:0.4.5"
classpath "net.ltgt.gradle:gradle-apt-plugin:0.10"
@@ -74,6 +79,8 @@
apply plugin: 'kotlin'
subprojects {
+ if (project.name == "native") return
+
apply plugin: 'kotlinx-serialization'
apply plugin: 'maven-publish'
@@ -119,23 +126,5 @@
}
}
- bintray {
- user = project.hasProperty('bintrayUser') ? project.property('bintrayUser') : System.getenv('BINTRAY_USER')
- key = project.hasProperty('bintrayApiKey') ? project.property('bintrayApiKey') : System.getenv('BINTRAY_API_KEY')
- publications = ['mavenProject']
- pkg {
- repo = 'kotlinx'
- name = 'kotlinx.serialization.runtime'
- userOrg = 'kotlin'
- licenses = ['Apache-2.0']
- vcsUrl = 'https://github.com/Kotlin/kotlinx.serialization'
- websiteUrl = 'https://github.com/Kotlin/kotlinx.serialization'
- issueTrackerUrl = 'https://github.com/Kotlin/kotlinx.serialization/issues'
-
- githubRepo = 'Kotlin/kotlinx.serialization'
- version {
- name = project.version
- }
- }
- }
+ apply plugin: 'com.jfrog.bintray'
}
diff --git a/gradle.properties b/gradle.properties
index 8bf5c71..cbae617 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -17,6 +17,7 @@
kotlin.version=1.2.50
kotlin.version.snapshot=1.2-SNAPSHOT
plugin.version=0.5.1
+konan.version=0.7
org.gradle.parallel=true
org.gradle.caching=true
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 1eb0ae4..7fc1809 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -19,4 +19,4 @@
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.5-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
diff --git a/json/common/build.gradle b/json/common/build.gradle
new file mode 100644
index 0000000..c68d322
--- /dev/null
+++ b/json/common/build.gradle
@@ -0,0 +1,12 @@
+apply plugin: 'kotlin-platform-common'
+
+sourceSets {
+ main.kotlin.srcDirs = ['src']
+}
+
+dependencies {
+ compile libraries.kotlin_stdlib_common
+
+ testCompile libraries.kotlin_test_annotations_common
+ testCompile libraries.kotlin_test_common
+}
diff --git a/json/common/src/kotlinx/serialization/json/JsonAst.kt b/json/common/src/kotlinx/serialization/json/JsonAst.kt
new file mode 100644
index 0000000..23318d4
--- /dev/null
+++ b/json/common/src/kotlinx/serialization/json/JsonAst.kt
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2018 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package kotlinx.serialization.json
+
+/**
+ * Root node for whole JSON DOM
+ */
+sealed class JsonElement
+
+sealed class JsonPrimitive : JsonElement() {
+ protected abstract val content: String
+
+ val asInt: Int get() = content.toInt()
+ val asLong: Long get() = content.toLong()
+
+ val asDouble: Double get() = content.toDouble()
+ val asFloat: Float get() = content.toFloat()
+
+ val asBoolean: Boolean get() = content.toBoolean()
+
+ val str: String get() = content
+}
+
+/**
+ * Represents quoted JSON strings
+ */
+data class JsonString(override val content: String): JsonPrimitive() {
+ private var quotedString: String? = null
+
+ override fun toString(): String = if (quotedString != null) quotedString!! else {
+ quotedString = buildString { printQuoted(content) }
+ quotedString!!
+ }
+}
+
+/**
+ * Represents unquoted JSON primitives (numbers, booleans and null)
+ */
+data class JsonLiteral(override val content: String): JsonPrimitive() {
+ constructor(number: Number): this(number.toString())
+ constructor(boolean: Boolean): this(boolean.toString())
+
+ override fun toString() = content
+}
+
+val JsonNull = JsonLiteral("null")
+
+data class JsonObject(val content: Map<String, JsonElement>) : JsonElement(), Map<String, JsonElement> by content {
+ fun getAsValue(key: String)= content[key] as? JsonPrimitive
+ fun getAsObject(key: String) = content[key] as? JsonObject
+ fun getAsArray(key: String) = content[key] as? JsonArray
+
+ override fun toString(): String {
+ return content.entries.joinToString(
+ prefix = "{",
+ postfix = "}",
+ transform = {(k, v) -> """"$k": $v"""}
+ )
+ }
+}
+
+data class JsonArray(val content: List<JsonElement>) : JsonElement(), List<JsonElement> by content {
+ fun getAsValue(index: Int) = content.getOrNull(index) as? JsonPrimitive
+ fun getAsObject(index: Int) = content.getOrNull(index) as? JsonObject
+ fun getAsArray(index: Int) = content.getOrNull(index) as? JsonArray
+
+ override fun toString() = content.joinToString(prefix = "[", postfix = "]")
+}
+
+
+class JsonTreeParser(val input: String) {
+ private val p: Parser = Parser(input)
+
+ private fun readObject(): JsonElement {
+ p.requireTc(TC_BEGIN_OBJ) { "Expected start of object" }
+ p.nextToken()
+ val result: MutableMap<String, JsonElement> = hashMapOf()
+ while (true) {
+ if (p.tc == TC_COMMA) p.nextToken()
+ if (!p.canBeginValue) break
+ val key = p.takeStr()
+ p.requireTc(TC_COLON) { "Expected ':'" }
+ p.nextToken()
+ val elem = read()
+ result[key] = elem
+ }
+ p.requireTc(TC_END_OBJ) { "Expected end of object" }
+ p.nextToken()
+ return JsonObject(result)
+ }
+
+ private fun readValue(asLiteral: Boolean = false): JsonElement {
+ val str = p.takeStr()
+ return if (asLiteral) JsonLiteral(str) else JsonString(str)
+ }
+
+ private fun readArray(): JsonElement {
+ p.requireTc(TC_BEGIN_LIST) { "Expected start of array" }
+ p.nextToken()
+ val result: MutableList<JsonElement> = arrayListOf()
+ while (true) {
+ if (p.tc == TC_COMMA) p.nextToken()
+ if (!p.canBeginValue) break
+ val elem = read()
+ result.add(elem)
+ }
+ p.requireTc(TC_END_LIST) { "Expected end of array" }
+ p.nextToken()
+ return JsonArray(result)
+ }
+
+ fun read(): JsonElement {
+ if (!p.canBeginValue) fail(p.curPos, "Can't begin reading value from here")
+ val tc = p.tc
+ return when (tc) {
+ TC_NULL -> JsonNull.also { p.nextToken() }
+ TC_STRING -> readValue(asLiteral = false)
+ TC_OTHER -> readValue(asLiteral = true)
+ TC_BEGIN_OBJ -> readObject()
+ TC_BEGIN_LIST -> readArray()
+ else -> fail(p.curPos, "Can't begin reading element")
+ }
+ }
+
+ fun readFully(): JsonElement {
+ val r = read()
+ p.requireTc(TC_EOF) { "Input wasn't consumed fully" }
+ return r
+ }
+}
diff --git a/runtime/common/src/main/kotlin/kotlinx/serialization/json/JsonParser.kt b/json/common/src/kotlinx/serialization/json/JsonParser.kt
similarity index 97%
rename from runtime/common/src/main/kotlin/kotlinx/serialization/json/JsonParser.kt
rename to json/common/src/kotlinx/serialization/json/JsonParser.kt
index 1a46f8d..6440fd7 100644
--- a/runtime/common/src/main/kotlin/kotlinx/serialization/json/JsonParser.kt
+++ b/json/common/src/kotlinx/serialization/json/JsonParser.kt
@@ -1,8 +1,5 @@
package kotlinx.serialization.json
-import kotlinx.serialization.SerializationException
-import kotlinx.serialization.internal.createString
-
// special strings
internal const val NULL = "null"
@@ -261,11 +258,11 @@
when (tc) {
TC_BEGIN_LIST, TC_BEGIN_OBJ -> tokenStack.add(tc)
TC_END_LIST -> {
- if (tokenStack.last() != TC_BEGIN_LIST) throw SerializationException("Invalid JSON at $curPos: found ] instead of }")
+ if (tokenStack.last() != TC_BEGIN_LIST) throw IllegalStateException("Invalid JSON at $curPos: found ] instead of }")
tokenStack.removeAt(tokenStack.size - 1)
}
TC_END_OBJ -> {
- if (tokenStack.last() != TC_BEGIN_OBJ) throw SerializationException("Invalid JSON at $curPos: found } instead of ]")
+ if (tokenStack.last() != TC_BEGIN_OBJ) throw IllegalStateException("Invalid JSON at $curPos: found } instead of ]")
tokenStack.removeAt(tokenStack.size - 1)
}
}
diff --git a/json/common/src/kotlinx/serialization/json/StringOps.kt b/json/common/src/kotlinx/serialization/json/StringOps.kt
new file mode 100644
index 0000000..48e97e8
--- /dev/null
+++ b/json/common/src/kotlinx/serialization/json/StringOps.kt
@@ -0,0 +1,54 @@
+package kotlinx.serialization.json
+
+/**
+ * Creates a string by concatenating given chars.
+ * Can be more efficient than `joinToString` on some platforms.
+ *
+ * charArrayOf('a','b','c').createString(2) = "ab"
+ */
+expect fun CharArray.createString(length: Int): String
+
+private fun toHexChar(i: Int) : Char {
+ val d = i and 0xf
+ return if (d < 10) (d + '0'.toInt()).toChar()
+ else (d - 10 + 'a'.toInt()).toChar()
+}
+
+/*
+ * Even though the actual size of this array is 92, it has to be the power of two, otherwise
+ * JVM cannot perform advanced range-check elimination and vectorization in printQuoted
+ */
+private val ESCAPE_CHARS: Array<String?> = arrayOfNulls<String>(128).apply {
+ for (c in 0..0x1f) {
+ val c1 = toHexChar(c shr 12)
+ val c2 = toHexChar(c shr 8)
+ val c3 = toHexChar(c shr 4)
+ val c4 = toHexChar(c)
+ this[c] = "\\u$c1$c2$c3$c4"
+ }
+ this['"'.toInt()] = "\\\""
+ this['\\'.toInt()] = "\\\\"
+ this['\t'.toInt()] = "\\t"
+ this['\b'.toInt()] = "\\b"
+ this['\n'.toInt()] = "\\n"
+ this['\r'.toInt()] = "\\r"
+ this[0x0c] = "\\f"
+}
+
+internal fun StringBuilder.printQuoted(value: String) {
+ append(STRING)
+ var lastPos = 0
+ val length = value.length
+ for (i in 0 until length) {
+ val c = value[i].toInt()
+ // Do not replace this constant with C2ESC_MAX (which is smaller than ESCAPE_CHARS size),
+ // otherwise JIT won't eliminate range check and won't vectorize this loop
+ if (c >= ESCAPE_CHARS.size) continue // no need to escape
+ val esc = ESCAPE_CHARS[c] ?: continue
+ append(value, lastPos, i) // flush prev
+ append(esc)
+ lastPos = i + 1
+ }
+ append(value, lastPos, length)
+ append(STRING)
+}
diff --git a/json/native/build.gradle b/json/native/build.gradle
new file mode 100644
index 0000000..2170b09
--- /dev/null
+++ b/json/native/build.gradle
@@ -0,0 +1,39 @@
+apply plugin: 'konan'
+
+konanArtifacts {
+ library('jsonparser') {
+ enableMultiplatform true
+ srcDir 'src'
+ srcDir project(':jsonparser').file('src')
+ }
+}
+
+apply plugin: 'maven-publish'
+apply plugin: 'com.jfrog.bintray'
+
+def localMavenRepo = "file://${new File(System.properties['user.home'] as String)}/.m2-kotlin-native"
+def remoteBintrayRepo ="https://dl.bintray.com/sandwwraith/generic/native-libs"
+
+publishing {
+ repositories {
+ maven {
+ url = remoteBintrayRepo
+ }
+ }
+}
+
+bintray {
+ user = project.hasProperty('bintrayUser') ? project.property('bintrayUser') : System.getenv('BINTRAY_USER')
+ key = project.hasProperty('bintrayApiKey') ? project.property('bintrayApiKey') : System.getenv('BINTRAY_API_KEY')
+ pkg {
+ userOrg = 'sandwwraith'
+ repo = 'generic'
+ name = "native-libs"
+ licenses = ['Apache-2.0']
+ vcsUrl = 'https://github.com/Kotlin/kotlinx.serialization'
+ }
+}
+
+bintrayUpload.doFirst {
+ publications = project.publishing.publications
+}
diff --git a/json/native/src/kotlinx/serialization/json/StringOps.kt b/json/native/src/kotlinx/serialization/json/StringOps.kt
new file mode 100644
index 0000000..4b93f27
--- /dev/null
+++ b/json/native/src/kotlinx/serialization/json/StringOps.kt
@@ -0,0 +1,7 @@
+package kotlinx.serialization.json
+
+actual fun CharArray.createString(length: Int): String =
+ StringBuilder().also {
+ it.insert(0, this)
+ it.length = length
+ }.toString()
diff --git a/runtime/common/build.gradle b/runtime/common/build.gradle
index f6b57da..dc022ea 100644
--- a/runtime/common/build.gradle
+++ b/runtime/common/build.gradle
@@ -18,6 +18,7 @@
dependencies {
compile libraries.kotlin_stdlib_common
+ compile project(':jsonparser')
testCompile libraries.kotlin_test_annotations_common
testCompile libraries.kotlin_test_common
diff --git a/runtime/common/src/main/kotlin/kotlinx/serialization/internal/CommonStrings.kt b/runtime/common/src/main/kotlin/kotlinx/serialization/internal/CommonStrings.kt
deleted file mode 100644
index 21b0e42..0000000
--- a/runtime/common/src/main/kotlin/kotlinx/serialization/internal/CommonStrings.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright 2017 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package kotlinx.serialization.internal
-
-/**
- * Creates a string by concatenating given chars.
- * Can be more efficient than `joinToString` on some platforms.
- *
- * charArrayOf('a','b','c').createString(2) = "ab"
- */
-expect fun CharArray.createString(length: Int): String
diff --git a/runtime/common/src/main/kotlin/kotlinx/serialization/json/JSON.kt b/runtime/common/src/main/kotlin/kotlinx/serialization/json/JSON.kt
index 34677be..a3c80ff 100644
--- a/runtime/common/src/main/kotlin/kotlinx/serialization/json/JSON.kt
+++ b/runtime/common/src/main/kotlin/kotlinx/serialization/json/JSON.kt
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
+@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
package kotlinx.serialization.json
import kotlinx.serialization.*
@@ -330,48 +330,3 @@
}
return false
}
-
-private fun toHexChar(i: Int) : Char {
- val d = i and 0xf
- return if (d < 10) (d + '0'.toInt()).toChar()
- else (d - 10 + 'a'.toInt()).toChar()
-}
-
-/*
- * Even though the actual size of this array is 92, it has to be the power of two, otherwise
- * JVM cannot perform advanced range-check elimination and vectorization in printQuoted
- */
-private val ESCAPE_CHARS: Array<String?> = arrayOfNulls<String>(128).apply {
- for (c in 0..0x1f) {
- val c1 = toHexChar(c shr 12)
- val c2 = toHexChar(c shr 8)
- val c3 = toHexChar(c shr 4)
- val c4 = toHexChar(c)
- this[c] = "\\u$c1$c2$c3$c4"
- }
- this['"'.toInt()] = "\\\""
- this['\\'.toInt()] = "\\\\"
- this['\t'.toInt()] = "\\t"
- this['\b'.toInt()] = "\\b"
- this['\n'.toInt()] = "\\n"
- this['\r'.toInt()] = "\\r"
- this[0x0c] = "\\f"
-}
-
-internal fun StringBuilder.printQuoted(value: String) {
- append(STRING)
- var lastPos = 0
- val length = value.length
- for (i in 0 until length) {
- val c = value[i].toInt()
- // Do not replace this constant with C2ESC_MAX (which is smaller than ESCAPE_CHARS size),
- // otherwise JIT won't eliminate range check and won't vectorize this loop
- if (c >= ESCAPE_CHARS.size) continue // no need to escape
- val esc = ESCAPE_CHARS[c] ?: continue
- append(value, lastPos, i) // flush prev
- append(esc)
- lastPos = i + 1
- }
- append(value, lastPos, length)
- append(STRING)
-}
diff --git a/runtime/common/src/main/kotlin/kotlinx/serialization/json/JsonAst.kt b/runtime/common/src/main/kotlin/kotlinx/serialization/json/JsonAst.kt
deleted file mode 100644
index 4e72010..0000000
--- a/runtime/common/src/main/kotlin/kotlinx/serialization/json/JsonAst.kt
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * Copyright 2018 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package kotlinx.serialization.json
-
-import kotlinx.serialization.*
-import kotlin.reflect.KClass
-
-/**
- * Root node for whole JSON DOM
- */
-sealed class JsonElement
-
-sealed class JsonPrimitive : JsonElement() {
- protected abstract val content: String
-
- val asInt: Int get() = content.toInt()
- val asLong: Long get() = content.toLong()
-
- val asDouble: Double get() = content.toDouble()
- val asFloat: Float get() = content.toFloat()
-
- val asBoolean: Boolean get() = content.toBoolean()
-
- val str: String get() = content
-}
-
-/**
- * Represents quoted JSON strings
- */
-data class JsonString(override val content: String): JsonPrimitive() {
- override fun toString() = buildString { printQuoted(content) }
-}
-
-/**
- * Represents unquoted JSON primitives (numbers, booleans and null)
- */
-data class JsonLiteral(override val content: String): JsonPrimitive() {
- override fun toString() = content
-}
-
-val JsonNull = JsonLiteral("null")
-
-data class JsonObject(val content: Map<String, JsonElement>) : JsonElement(), Map<String, JsonElement> by content {
- fun getAsValue(key: String)= content[key] as? JsonPrimitive
- fun getAsObject(key: String) = content[key] as? JsonObject
- fun getAsArray(key: String) = content[key] as? JsonArray
-
- override fun toString(): String {
- return content.entries.joinToString(
- prefix = "{",
- postfix = "}",
- transform = {(k, v) -> """"$k": $v"""}
- )
- }
-}
-
-data class JsonArray(val content: List<JsonElement>) : JsonElement(), List<JsonElement> by content {
- fun getAsValue(index: Int) = content.getOrNull(index) as? JsonPrimitive
- fun getAsObject(index: Int) = content.getOrNull(index) as? JsonObject
- fun getAsArray(index: Int) = content.getOrNull(index) as? JsonArray
-
- override fun toString() = content.joinToString(prefix = "[", postfix = "]")
-}
-
-
-class JsonTreeParser(val input: String) {
- private val p: Parser = Parser(input)
-
- private fun readObject(): JsonElement {
- p.requireTc(TC_BEGIN_OBJ) { "Expected start of object" }
- p.nextToken()
- val result: MutableMap<String, JsonElement> = hashMapOf()
- while (true) {
- if (p.tc == TC_COMMA) p.nextToken()
- if (!p.canBeginValue) break
- val key = p.takeStr()
- p.requireTc(TC_COLON) { "Expected ':'" }
- p.nextToken()
- val elem = read()
- result[key] = elem
- }
- p.requireTc(TC_END_OBJ) { "Expected end of object" }
- p.nextToken()
- return JsonObject(result)
- }
-
- private fun readValue(asLiteral: Boolean = false): JsonElement {
- val str = p.takeStr()
- return if (asLiteral) JsonLiteral(str) else JsonString(str)
- }
-
- private fun readArray(): JsonElement {
- p.requireTc(TC_BEGIN_LIST) { "Expected start of array" }
- p.nextToken()
- val result: MutableList<JsonElement> = arrayListOf()
- while (true) {
- if (p.tc == TC_COMMA) p.nextToken()
- if (!p.canBeginValue) break
- val elem = read()
- result.add(elem)
- }
- p.requireTc(TC_END_LIST) { "Expected end of array" }
- p.nextToken()
- return JsonArray(result)
- }
-
- fun read(): JsonElement {
- if (!p.canBeginValue) fail(p.curPos, "Can't begin reading value from here")
- val tc = p.tc
- return when (tc) {
- TC_NULL -> JsonNull.also { p.nextToken() }
- TC_STRING -> readValue(asLiteral = false)
- TC_OTHER -> readValue(asLiteral = true)
- TC_BEGIN_OBJ -> readObject()
- TC_BEGIN_LIST -> readArray()
- else -> fail(p.curPos, "Can't begin reading element")
- }
- }
-
- fun readFully(): JsonElement {
- val r = read()
- p.requireTc(TC_EOF) { "Input wasn't consumed fully" }
- return r
- }
-}
-
-
-class JsonTreeMapper(val context: SerialContext? = null) {
- inline fun <reified T : Any> readTree(tree: JsonElement): T = readTree(tree, context.klassSerializer(T::class))
-
- fun <T> readTree(obj: JsonElement, loader: KSerialLoader<T>): T {
- if (obj !is JsonObject) throw SerializationException("Can't deserialize primitive on root level")
- return JsonTreeInput(obj).read(loader)
- }
-
- private abstract inner class AbstractJsonTreeInput(open val obj: JsonElement): NamedValueInput() {
- init {
- this.context = this@JsonTreeMapper.context
- }
-
- override fun composeName(parentName: String, childName: String): String = childName
-
-
- override fun readBegin(desc: KSerialClassDesc, vararg typeParams: KSerializer<*>): KInput {
- val curObj = currentTagOrNull?.let { currentElement(it) } ?: obj
- // todo: more informative exceptions instead of ClassCast
- return when (desc.kind) {
- KSerialClassKind.LIST, KSerialClassKind.SET -> JsonTreeListInput(curObj as JsonArray)
- KSerialClassKind.MAP -> JsonTreeMapInput(curObj as JsonObject)
- KSerialClassKind.ENTRY -> JsonTreeMapEntryInput(curObj, currentTag)
- else -> JsonTreeInput(curObj as JsonObject)
- }
- }
-
- protected open fun getValue(tag: String): JsonPrimitive {
- val currentElement = currentElement(tag)
- return currentElement as? JsonPrimitive ?: throw SerializationException("Expected from $tag to be primitive but found $currentElement")
- }
-
- protected abstract fun currentElement(tag: String): JsonElement
-
- override fun readTaggedChar(tag: String): Char {
- val o = getValue(tag)
- return if (o.str.length == 1) o.str[0] else throw SerializationException("$o can't be represented as Char")
- }
-
- override fun <E : Enum<E>> readTaggedEnum(tag: String, enumClass: KClass<E>): E =
- enumFromName(enumClass, (getValue(tag).str))
-
- override fun readTaggedNull(tag: String): Nothing? = null
- override fun readTaggedNotNullMark(tag: String) = currentElement(tag) !== JsonNull
-
- override fun readTaggedUnit(tag: String) {
- return
- }
-
- override fun readTaggedBoolean(tag: String): Boolean = getValue(tag).asBoolean
- override fun readTaggedByte(tag: String): Byte = getValue(tag).asInt.toByte()
- override fun readTaggedShort(tag: String) = getValue(tag).asInt.toShort()
- override fun readTaggedInt(tag: String) = getValue(tag).asInt
- override fun readTaggedLong(tag: String) = getValue(tag).asLong
- override fun readTaggedFloat(tag: String) = getValue(tag).asFloat
- override fun readTaggedDouble(tag: String) = getValue(tag).asDouble
- override fun readTaggedString(tag: String) = getValue(tag).str
-
- }
-
- private open inner class JsonTreeInput(override val obj: JsonObject) : AbstractJsonTreeInput(obj) {
-
- private var pos = 0
-
- override fun readElement(desc: KSerialClassDesc): Int {
- while (pos < desc.associatedFieldsCount) {
- val name = desc.getTag(pos++)
- if (name in obj) return pos - 1
- }
- return READ_DONE
- }
-
- override fun currentElement(tag: String): JsonElement {
- return obj.getValue(tag)
- }
-
- }
-
- private inner class JsonTreeMapEntryInput(override val obj: JsonElement, val cTag: String): AbstractJsonTreeInput(obj) {
-
- override fun currentElement(tag: String): JsonElement = if (tag == "key") {
- JsonString(cTag)
- } else {
- check(tag == "value") {"Found unexpected tag: $tag"}
- obj
- }
-
- override fun readElement(desc: KSerialClassDesc): Int = READ_ALL
- }
-
- private inner class JsonTreeMapInput(override val obj: JsonObject): JsonTreeInput(obj) {
-
- private val keys = obj.keys.toList()
- private val size: Int = keys.size
- private var pos = 0
-
- override fun elementName(desc: KSerialClassDesc, index: Int): String {
- val i = index - 1
- return keys[i]
- }
-
- override fun readElement(desc: KSerialClassDesc): Int {
- while (pos < size) {
- pos++
- return pos
- }
- return READ_DONE
- }
- }
-
- private inner class JsonTreeListInput(override val obj: JsonArray): AbstractJsonTreeInput(obj) {
-
- override fun currentElement(tag: String): JsonElement {
- return obj[tag.toInt()]
- }
-
- private val size = obj.content.size
- private var pos = 0 // 0st element is SIZE. use it?
-
- override fun elementName(desc: KSerialClassDesc, index: Int): String = (index - 1).toString()
-
- override fun readElement(desc: KSerialClassDesc): Int {
- while (pos < size) {
- pos++
- return pos
- }
- return READ_DONE
- }
- }
-}
diff --git a/runtime/common/src/main/kotlin/kotlinx/serialization/json/JsonTreeMapper.kt b/runtime/common/src/main/kotlin/kotlinx/serialization/json/JsonTreeMapper.kt
new file mode 100644
index 0000000..68b32a3
--- /dev/null
+++ b/runtime/common/src/main/kotlin/kotlinx/serialization/json/JsonTreeMapper.kt
@@ -0,0 +1,253 @@
+/*
+ * Copyright 2018 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package kotlinx.serialization.json
+
+import kotlinx.serialization.*
+import kotlinx.serialization.internal.SIZE_INDEX
+import kotlin.reflect.KClass
+
+class JsonTreeMapper(val context: SerialContext? = null) {
+ inline fun <reified T : Any> readTree(tree: JsonElement): T = readTree(tree, context.klassSerializer(T::class))
+
+ fun <T> readTree(obj: JsonElement, loader: KSerialLoader<T>): T {
+ if (obj !is JsonObject) throw SerializationException("Can't deserialize primitive on root level")
+ return JsonTreeInput(obj).read(loader)
+ }
+
+ fun <T> writeTree(obj: T, saver: KSerialSaver<T>): JsonElement {
+ lateinit var result: JsonElement
+ val output = JsonTreeOutput { result = it }
+ output.write(saver, obj)
+ return result
+ }
+
+ private abstract inner class AbstractJsonTreeOutput(val nodeConsumer: (JsonElement) -> Unit) : NamedValueOutput() {
+ init {
+ this.context = this@JsonTreeMapper.context
+ }
+
+ override fun composeName(parentName: String, childName: String): String = childName
+
+ abstract fun putElement(key: String, element: JsonElement)
+ abstract fun getCurrent(): JsonElement
+
+ override fun writeTaggedNull(tag: String) = putElement(tag, JsonNull)
+
+ override fun writeTaggedInt(tag: String, value: Int) = putElement(tag, JsonLiteral(value))
+ override fun writeTaggedByte(tag: String, value: Byte) = putElement(tag, JsonLiteral(value))
+ override fun writeTaggedShort(tag: String, value: Short) = putElement(tag, JsonLiteral(value))
+ override fun writeTaggedLong(tag: String, value: Long) = putElement(tag, JsonLiteral(value))
+ override fun writeTaggedFloat(tag: String, value: Float) = putElement(tag, JsonLiteral(value))
+ override fun writeTaggedDouble(tag: String, value: Double) = putElement(tag, JsonLiteral(value))
+ override fun writeTaggedBoolean(tag: String, value: Boolean) = putElement(tag, JsonLiteral(value))
+
+ override fun writeTaggedChar(tag: String, value: Char) = putElement(tag, JsonString(value.toString()))
+ override fun writeTaggedString(tag: String, value: String) = putElement(tag, JsonString(value))
+ override fun <E : Enum<E>> writeTaggedEnum(tag: String, enumClass: KClass<E>, value: E) = putElement(tag, JsonString(value.toString()))
+
+ override fun writeTaggedValue(tag: String, value: Any) {
+ putElement(tag, JsonString(value.toString()))
+ }
+
+ override fun writeBegin(desc: KSerialClassDesc, vararg typeParams: KSerializer<*>): KOutput {
+ val consumer =
+ if (currentTagOrNull == null) nodeConsumer
+ else { node -> putElement(currentTag, node) }
+ return when (desc.kind) {
+ KSerialClassKind.LIST, KSerialClassKind.SET -> JsonTreeListOutput(consumer)
+ KSerialClassKind.MAP -> JsonTreeMapOutput(consumer)
+ KSerialClassKind.ENTRY -> JsonTreeEntryOutput(this@AbstractJsonTreeOutput::putElement)
+ else -> JsonTreeOutput(consumer)
+ }
+ }
+
+ override fun writeFinished(desc: KSerialClassDesc) {
+ nodeConsumer(getCurrent())
+ }
+ }
+
+ private open inner class JsonTreeOutput(nodeConsumer: (JsonElement) -> Unit) :
+ AbstractJsonTreeOutput(nodeConsumer) {
+ private val map: MutableMap<String, JsonElement> = hashMapOf()
+
+ override fun putElement(key: String, element: JsonElement) {
+ map[key] = element
+ }
+
+ override fun getCurrent(): JsonElement = JsonObject(map)
+ }
+
+ private inner class JsonTreeMapOutput(nodeConsumer: (JsonElement) -> Unit) : JsonTreeOutput(nodeConsumer) {
+ override fun shouldWriteElement(desc: KSerialClassDesc, tag: String, index: Int): Boolean = index != SIZE_INDEX
+ }
+
+ private inner class JsonTreeListOutput(nodeConsumer: (JsonElement) -> Unit) : AbstractJsonTreeOutput(nodeConsumer) {
+ private val array: ArrayList<JsonElement> = arrayListOf()
+
+ override fun shouldWriteElement(desc: KSerialClassDesc, tag: String, index: Int): Boolean = index != SIZE_INDEX
+
+ override fun putElement(key: String, element: JsonElement) {
+ val idx = key.toInt() - 1
+ array.add(idx, element)
+ }
+
+ override fun getCurrent(): JsonElement = JsonArray(array)
+ }
+
+ private inner class JsonTreeEntryOutput(val entryConsumer: (String, JsonElement) -> Unit) :
+ AbstractJsonTreeOutput({ throw IllegalStateException("Use entryConsumer instead") }) {
+
+ private lateinit var elem: JsonElement
+ private lateinit var tag: String
+
+ override fun putElement(key: String, element: JsonElement) {
+ if (key != "key") {
+ elem = element
+ } else {
+ check(element is JsonString) { "Expected tag to be JsonString" }
+ tag = (element as JsonString).str
+ }
+ }
+
+ override fun getCurrent(): JsonElement = elem
+
+ override fun writeFinished(desc: KSerialClassDesc) {
+ entryConsumer(tag, elem)
+ }
+ }
+
+ private abstract inner class AbstractJsonTreeInput(open val obj: JsonElement): NamedValueInput() {
+ init {
+ this.context = this@JsonTreeMapper.context
+ }
+
+ override fun composeName(parentName: String, childName: String): String = childName
+
+ private inline fun <reified T: JsonElement> checkCast(obj: JsonElement): T {
+ check(obj is T) { "Expected ${T::class} but found ${obj::class}" }
+ return obj as T
+ }
+
+ override fun readBegin(desc: KSerialClassDesc, vararg typeParams: KSerializer<*>): KInput {
+ val curObj = currentTagOrNull?.let { currentElement(it) } ?: obj
+ return when (desc.kind) {
+ KSerialClassKind.LIST, KSerialClassKind.SET -> JsonTreeListInput(checkCast(curObj))
+ KSerialClassKind.MAP -> JsonTreeMapInput(checkCast(curObj))
+ KSerialClassKind.ENTRY -> JsonTreeMapEntryInput(curObj, currentTag)
+ else -> JsonTreeInput(checkCast(curObj))
+ }
+ }
+
+ protected open fun getValue(tag: String): JsonPrimitive {
+ val currentElement = currentElement(tag)
+ return currentElement as? JsonPrimitive ?: throw SerializationException("Expected from $tag to be primitive but found $currentElement")
+ }
+
+ protected abstract fun currentElement(tag: String): JsonElement
+
+ override fun readTaggedChar(tag: String): Char {
+ val o = getValue(tag)
+ return if (o.str.length == 1) o.str[0] else throw SerializationException("$o can't be represented as Char")
+ }
+
+ override fun <E : Enum<E>> readTaggedEnum(tag: String, enumClass: KClass<E>): E =
+ enumFromName(enumClass, (getValue(tag).str))
+
+ override fun readTaggedNull(tag: String): Nothing? = null
+ override fun readTaggedNotNullMark(tag: String) = currentElement(tag) !== JsonNull
+
+ override fun readTaggedUnit(tag: String) {
+ return
+ }
+
+ override fun readTaggedBoolean(tag: String): Boolean = getValue(tag).asBoolean
+ override fun readTaggedByte(tag: String): Byte = getValue(tag).asInt.toByte()
+ override fun readTaggedShort(tag: String) = getValue(tag).asInt.toShort()
+ override fun readTaggedInt(tag: String) = getValue(tag).asInt
+ override fun readTaggedLong(tag: String) = getValue(tag).asLong
+ override fun readTaggedFloat(tag: String) = getValue(tag).asFloat
+ override fun readTaggedDouble(tag: String) = getValue(tag).asDouble
+ override fun readTaggedString(tag: String) = getValue(tag).str
+
+ }
+
+ private open inner class JsonTreeInput(override val obj: JsonObject) : AbstractJsonTreeInput(obj) {
+
+ private var pos = 0
+
+ override fun readElement(desc: KSerialClassDesc): Int {
+ while (pos < desc.associatedFieldsCount) {
+ val name = desc.getTag(pos++)
+ if (name in obj) return pos - 1
+ }
+ return READ_DONE
+ }
+
+ override fun currentElement(tag: String): JsonElement = obj.getValue(tag)
+
+ }
+
+ private inner class JsonTreeMapEntryInput(override val obj: JsonElement, val cTag: String): AbstractJsonTreeInput(obj) {
+
+ override fun currentElement(tag: String): JsonElement = if (tag == "key") {
+ JsonString(cTag)
+ } else {
+ check(tag == "value") { "Found unexpected tag: $tag" }
+ obj
+ }
+ }
+
+ private inner class JsonTreeMapInput(override val obj: JsonObject): JsonTreeInput(obj) {
+
+ private val keys = obj.keys.toList()
+ private val size: Int = keys.size
+ private var pos = 0
+
+ override fun elementName(desc: KSerialClassDesc, index: Int): String {
+ val i = index - 1
+ return keys[i]
+ }
+
+ override fun readElement(desc: KSerialClassDesc): Int {
+ while (pos < size) {
+ pos++
+ return pos
+ }
+ return READ_DONE
+ }
+ }
+
+ private inner class JsonTreeListInput(override val obj: JsonArray): AbstractJsonTreeInput(obj) {
+
+ override fun currentElement(tag: String): JsonElement {
+ return obj[tag.toInt()]
+ }
+
+ private val size = obj.content.size
+ private var pos = 0 // 0st element is SIZE. use it?
+
+ override fun elementName(desc: KSerialClassDesc, index: Int): String = (index - 1).toString()
+
+ override fun readElement(desc: KSerialClassDesc): Int {
+ while (pos < size) {
+ pos++
+ return pos
+ }
+ return READ_DONE
+ }
+ }
+}
diff --git a/runtime/common/src/test/kotlin/kotlinx/serialization/json/JsonTreeTest.kt b/runtime/common/src/test/kotlin/kotlinx/serialization/json/JsonTreeTest.kt
index 315b4dc..254c5d2 100644
--- a/runtime/common/src/test/kotlin/kotlinx/serialization/json/JsonTreeTest.kt
+++ b/runtime/common/src/test/kotlin/kotlinx/serialization/json/JsonTreeTest.kt
@@ -43,69 +43,104 @@
private fun prepare(s: String): JsonElement = JsonTreeParser(s).readFully()
@Test
- fun dynamicSimpleTest() {
- val dyn = prepare("{a: 42}")
- val parsed = JsonTreeMapper().readTree(dyn, Data.serializer())
+ fun readTreeSimple() {
+ val tree = prepare("{a: 42}")
+ val parsed = JsonTreeMapper().readTree(tree, Data.serializer())
assertEquals(Data(42), parsed)
}
@Test
- fun dynamicNestedTest() {
- val dyn = prepare("""{s:"foo", d:{a:42}}""")
- val parsed = JsonTreeMapper().readTree<DataWrapper>(dyn)
+ fun readTreeNested() {
+ val tree = prepare("""{s:"foo", d:{a:42}}""")
+ val parsed = JsonTreeMapper().readTree<DataWrapper>(tree)
val expected = DataWrapper("foo", Data(42))
assertEquals(expected, parsed)
assertEquals(3, parsed.s.length)
}
@Test
- fun dynamicAllTypesTest() {
- val dyn = prepare("""{ b: 1, s: 2, i: 3, f: 1.0, d: 42.0, c: "a", B: true, S: "str"}""")
+ fun readTreeAllTypes() {
+ val tree = prepare("""{ b: 1, s: 2, i: 3, f: 1.0, d: 42.0, c: "a", B: true, S: "str"}""")
val kotlinObj = AllTypes(1, 2, 3, 1.0f, 42.0, 'a', true, "str")
- assertEquals(kotlinObj, JsonTreeMapper().readTree(dyn))
+ assertEquals(kotlinObj, JsonTreeMapper().readTree(tree))
}
@Test
- fun dynamicNullableTest() {
- val dyn1 = prepare("""{s:"foo", d: null}""")
- val dyn2 = prepare("""{s:"foo"}""")
+ fun readTreeNullable() {
+ val tree1 = prepare("""{s:"foo", d: null}""")
+ val tree2 = prepare("""{s:"foo"}""")
- assertEquals(DataWrapper("foo", null), JsonTreeMapper().readTree<DataWrapper>(dyn1))
- assertFailsWith(MissingFieldException::class) { JsonTreeMapper().readTree<DataWrapper>(dyn2) }
+ assertEquals(DataWrapper("foo", null), JsonTreeMapper().readTree<DataWrapper>(tree1))
+ assertFailsWith(MissingFieldException::class) { JsonTreeMapper().readTree<DataWrapper>(tree2) }
}
@Test
- fun dynamicOptionalTest() {
- val dyn1 = prepare("""{s:"foo", d: null}""")
- val dyn2 = prepare("""{s:"foo"}""")
+ fun readTreeOptional() {
+ val tree1 = prepare("""{s:"foo", d: null}""")
+ val tree2 = prepare("""{s:"foo"}""")
- assertEquals(DataWrapperOptional("foo", null), JsonTreeMapper().readTree<DataWrapperOptional>(dyn1))
- assertEquals(DataWrapperOptional("foo", null), JsonTreeMapper().readTree<DataWrapperOptional>(dyn2))
+ assertEquals(DataWrapperOptional("foo", null), JsonTreeMapper().readTree<DataWrapperOptional>(tree1))
+ assertEquals(DataWrapperOptional("foo", null), JsonTreeMapper().readTree<DataWrapperOptional>(tree2))
}
@Test
- fun dynamicListTest() {
- val dyn1 = prepare("""{l:[1,2]}""")
- val dyn15 = prepare("""{l:[{a:42},{a:43}]}""")
- val dyn2 = prepare("""{l:[[],[{a:42}]]}""")
+ fun readTreeList() {
+ val tree1 = prepare("""{l:[1,2]}""")
+ val tree2 = prepare("""{l:[{a:42},{a:43}]}""")
+ val tree3 = prepare("""{l:[[],[{a:42}]]}""")
- assertEquals(IntList(listOf(1, 2)), JsonTreeMapper().readTree<IntList>(dyn1))
- assertEquals(DataList(listOf(Data(42), Data(43))), JsonTreeMapper().readTree<DataList>(dyn15))
- assertEquals(ListOfLists(listOf(listOf(), listOf(Data(42)))), JsonTreeMapper().readTree<ListOfLists>(dyn2))
+ assertEquals(IntList(listOf(1, 2)), JsonTreeMapper().readTree<IntList>(tree1))
+ assertEquals(DataList(listOf(Data(42), Data(43))), JsonTreeMapper().readTree<DataList>(tree2))
+ assertEquals(ListOfLists(listOf(listOf(), listOf(Data(42)))), JsonTreeMapper().readTree<ListOfLists>(tree3))
}
@Test
- fun dynamicMapTest() {
+ fun readTreeMap() {
val dyn = prepare("{m : {\"a\": 1, \"b\" : 2}}")
val m = MapWrapper(mapOf("a" to 1, "b" to 2))
assertEquals(m, JsonTreeMapper().readTree<MapWrapper>(dyn))
}
@Test
- fun dynamicMapComplexTest() {
+ fun readTreeComplexMap() {
val dyn = prepare("{m : {1: {a: 42}, 2: {a: 43}}}")
val m = ComplexMapWrapper(mapOf("1" to Data(42), "2" to Data(43)))
assertEquals(m, JsonTreeMapper().readTree<ComplexMapWrapper>(dyn))
}
+
+ private inline fun <reified T: Any> writeAndTest(obj: T, printDiagnostics: Boolean = false): Pair<JsonElement, T> {
+ val serial = T::class.serializer()
+ val tree = JsonTreeMapper().writeTree(obj, serial)
+ val str = tree.toString()
+ if (printDiagnostics) println(str)
+ val restored = JsonTreeMapper().readTree(JsonTreeParser(str).readFully(), serial)
+ assertEquals(obj, restored)
+ return tree to restored
+ }
+
+ @Test
+ fun saveSimpleNestedTree() {
+ writeAndTest(DataWrapper("foo", Data(42)))
+ }
+
+ @Test
+ fun saveComplexMapTree() {
+ writeAndTest(ComplexMapWrapper(mapOf("foo" to Data(42), "bar" to Data(43))))
+ }
+
+ @Test
+ fun saveNestedLists() {
+ writeAndTest(ListOfLists(listOf(listOf(), listOf(Data(1), Data(2)))))
+ }
+
+ @Test
+ fun saveOptional() {
+ writeAndTest(DataWrapperOptional("foo", null))
+ }
+
+ @Test
+ fun saveAllTypes() {
+ writeAndTest(AllTypes(1, -2, 100500, 0.0f, 2048.2, 'a', true, "foobar"))
+ }
}
diff --git a/runtime/js/build.gradle b/runtime/js/build.gradle
index 08e7b34..f0edff4 100644
--- a/runtime/js/build.gradle
+++ b/runtime/js/build.gradle
@@ -27,6 +27,7 @@
dependencies {
expectedBy project(':common')
+ expectedBy project(':jsonparser')
compile libraries.kotlin_stdlib_js
testCompile libraries.kotlin_test_js
@@ -71,4 +72,4 @@
if (project.hasProperty("tests")) args += ["-f", project.property('tests')]
}
-test.dependsOn runQunit
\ No newline at end of file
+test.dependsOn runQunit
diff --git a/runtime/js/src/main/kotlin/kotlinx/serialization/internal/Strings.kt b/runtime/js/src/main/kotlin/kotlinx/serialization/internal/Strings.kt
deleted file mode 100644
index 77eb924..0000000
--- a/runtime/js/src/main/kotlin/kotlinx/serialization/internal/Strings.kt
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2017 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package kotlinx.serialization.internal
-
-actual fun CharArray.createString(length: Int): String =
- joinToString(separator = "", limit = length, truncated = "")
diff --git a/runtime/js/src/main/kotlin/kotlinx/serialization/json/StringOpsImpl.kt b/runtime/js/src/main/kotlin/kotlinx/serialization/json/StringOpsImpl.kt
new file mode 100644
index 0000000..5a4f59e
--- /dev/null
+++ b/runtime/js/src/main/kotlin/kotlinx/serialization/json/StringOpsImpl.kt
@@ -0,0 +1,4 @@
+package kotlinx.serialization.json
+
+actual fun CharArray.createString(length: Int): String =
+ joinToString(separator = "", limit = length, truncated = "")
diff --git a/runtime/js/src/test/kotlin/kotlinx/serialization/StringTest.kt b/runtime/js/src/test/kotlin/kotlinx/serialization/StringTest.kt
index 8b3b25e..f24c854 100644
--- a/runtime/js/src/test/kotlin/kotlinx/serialization/StringTest.kt
+++ b/runtime/js/src/test/kotlin/kotlinx/serialization/StringTest.kt
@@ -17,7 +17,7 @@
package kotlinx.serialization
import kotlinx.serialization.internal.HexConverter
-import kotlinx.serialization.internal.createString
+import kotlinx.serialization.json.createString
import kotlin.test.Test
import kotlin.test.assertEquals
diff --git a/runtime/jvm/build.gradle b/runtime/jvm/build.gradle
index 3c25385..6a89ead 100644
--- a/runtime/jvm/build.gradle
+++ b/runtime/jvm/build.gradle
@@ -53,6 +53,7 @@
dependencies {
expectedBy project(':common')
+ expectedBy project(':jsonparser')
compile libraries.kotlin_stdlib
diff --git a/runtime/jvm/src/main/kotlin/kotlinx/serialization/internal/Strings.kt b/runtime/jvm/src/main/kotlin/kotlinx/serialization/internal/Strings.kt
deleted file mode 100644
index 5e62045..0000000
--- a/runtime/jvm/src/main/kotlin/kotlinx/serialization/internal/Strings.kt
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2017 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package kotlinx.serialization.internal
-
-actual fun CharArray.createString(length: Int): String =
- String(this, 0, length)
diff --git a/runtime/jvm/src/main/kotlin/kotlinx/serialization/json/StringOpsImpl.kt b/runtime/jvm/src/main/kotlin/kotlinx/serialization/json/StringOpsImpl.kt
new file mode 100644
index 0000000..f9f2ff6
--- /dev/null
+++ b/runtime/jvm/src/main/kotlin/kotlinx/serialization/json/StringOpsImpl.kt
@@ -0,0 +1,4 @@
+package kotlinx.serialization.json
+
+actual fun CharArray.createString(length: Int): String =
+ String(this, 0, length)
diff --git a/settings.gradle b/settings.gradle
index 18de8fd..49a11d8 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -19,11 +19,15 @@
include ':common'
include ':jvm'
include ':js'
+include ':native'
+include ':jsonparser'
include ':configparser'
include ':benchmark'
project(':common').projectDir = file('./runtime/common')
project(':jvm').projectDir = file('./runtime/jvm')
project(':js').projectDir = file('./runtime/js')
+project(':native').projectDir = file('./json/native')
+project(':jsonparser').projectDir = file('./json/common')
project(':configparser').projectDir = file('./formats/config')
project(':benchmark').projectDir = file('./benchmark')