Skip to content

Commit df3a161

Browse files
authored
Improved okio support (#1982)
1 parent 4524b65 commit df3a161

File tree

6 files changed

+54
-71
lines changed

6 files changed

+54
-71
lines changed

benchmark/src/jmh/kotlin/kotlinx/benchmarks/json/JacksonComparisonBenchmark.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import com.fasterxml.jackson.databind.*
44
import com.fasterxml.jackson.module.kotlin.*
55
import kotlinx.serialization.*
66
import kotlinx.serialization.json.*
7-
import kotlinx.serialization.json.okio.encodeToSink
7+
import kotlinx.serialization.json.okio.encodeToBufferedSink
88
import okio.blackholeSink
99
import okio.buffer
1010
import org.openjdk.jmh.annotations.*
@@ -97,7 +97,7 @@ open class JacksonComparisonBenchmark {
9797
fun kotlinToStream() = Json.encodeToStream(DefaultPixelEvent.serializer(), data, devNullStream)
9898

9999
@Benchmark
100-
fun kotlinToOkio() = Json.encodeToSink(DefaultPixelEvent.serializer(), data, devNullSink)
100+
fun kotlinToOkio() = Json.encodeToBufferedSink(DefaultPixelEvent.serializer(), data, devNullSink)
101101

102102
@Benchmark
103103
fun kotlinToStringWithEscapes(): String = Json.encodeToString(DefaultPixelEvent.serializer(), dataWithEscapes)
@@ -109,7 +109,7 @@ open class JacksonComparisonBenchmark {
109109
fun kotlinSmallToStream() = Json.encodeToStream(SmallDataClass.serializer(), smallData, devNullStream)
110110

111111
@Benchmark
112-
fun kotlinSmallToOkio() = Json.encodeToSink(SmallDataClass.serializer(), smallData, devNullSink)
112+
fun kotlinSmallToOkio() = Json.encodeToBufferedSink(SmallDataClass.serializer(), smallData, devNullSink)
113113

114114
@Benchmark
115115
fun jacksonFromString(): DefaultPixelEvent = objectMapper.readValue(stringData, DefaultPixelEvent::class.java)
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
public final class kotlinx/serialization/json/okio/OkioStreamsKt {
2-
public static final fun decodeFromSource (Lkotlinx/serialization/json/Json;Lkotlinx/serialization/DeserializationStrategy;Lokio/Source;)Ljava/lang/Object;
3-
public static final fun decodeSourceToSequence (Lkotlinx/serialization/json/Json;Lokio/Source;Lkotlinx/serialization/DeserializationStrategy;Lkotlinx/serialization/json/DecodeSequenceMode;)Lkotlin/sequences/Sequence;
4-
public static synthetic fun decodeSourceToSequence$default (Lkotlinx/serialization/json/Json;Lokio/Source;Lkotlinx/serialization/DeserializationStrategy;Lkotlinx/serialization/json/DecodeSequenceMode;ILjava/lang/Object;)Lkotlin/sequences/Sequence;
5-
public static final fun encodeToSink (Lkotlinx/serialization/json/Json;Lkotlinx/serialization/SerializationStrategy;Ljava/lang/Object;Lokio/Sink;)V
2+
public static final fun decodeBufferedSourceToSequence (Lkotlinx/serialization/json/Json;Lokio/BufferedSource;Lkotlinx/serialization/DeserializationStrategy;Lkotlinx/serialization/json/DecodeSequenceMode;)Lkotlin/sequences/Sequence;
3+
public static synthetic fun decodeBufferedSourceToSequence$default (Lkotlinx/serialization/json/Json;Lokio/BufferedSource;Lkotlinx/serialization/DeserializationStrategy;Lkotlinx/serialization/json/DecodeSequenceMode;ILjava/lang/Object;)Lkotlin/sequences/Sequence;
4+
public static final fun decodeFromBufferedSource (Lkotlinx/serialization/json/Json;Lkotlinx/serialization/DeserializationStrategy;Lokio/BufferedSource;)Ljava/lang/Object;
5+
public static final fun encodeToBufferedSink (Lkotlinx/serialization/json/Json;Lkotlinx/serialization/SerializationStrategy;Ljava/lang/Object;Lokio/BufferedSink;)V
66
}
77

formats/json-okio/commonMain/src/kotlinx/serialization/json/okio/OkioStreams.kt

Lines changed: 23 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
* Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

5+
@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
6+
57
package kotlinx.serialization.json.okio
68

79
import kotlinx.serialization.*
@@ -16,19 +18,16 @@ import okio.*
1618
/**
1719
* Serializes the [value] with [serializer] into a [target] using JSON format and UTF-8 encoding.
1820
*
19-
* If [target] is not a [BufferedSink] then called [Sink.buffer] for it to create buffered wrapper.
20-
*
2121
* @throws [SerializationException] if the given value cannot be serialized to JSON.
2222
* @throws [okio.IOException] If an I/O error occurs and sink can't be written to.
2323
*/
2424
@ExperimentalSerializationApi
25-
public fun <T> Json.encodeToSink(
25+
public fun <T> Json.encodeToBufferedSink(
2626
serializer: SerializationStrategy<T>,
2727
value: T,
28-
target: Sink
28+
target: BufferedSink
2929
) {
30-
val buffered = if (target is BufferedSink) target else target.buffer()
31-
val writer = JsonToOkioStreamWriter(buffered)
30+
val writer = JsonToOkioStreamWriter(target)
3231
try {
3332
encodeByWriter(writer, serializer, value)
3433
} finally {
@@ -45,95 +44,85 @@ public fun <T> Json.encodeToSink(
4544
* @throws [okio.IOException] If an I/O error occurs and sink can't be written to.
4645
*/
4746
@ExperimentalSerializationApi
48-
public inline fun <reified T> Json.encodeToSink(
47+
public inline fun <reified T> Json.encodeToBufferedSink(
4948
value: T,
50-
target: Sink
51-
): Unit = encodeToSink(serializersModule.serializer(), value, target)
49+
target: BufferedSink
50+
): Unit = encodeToBufferedSink(serializersModule.serializer(), value, target)
5251

5352

5453
/**
5554
* Deserializes JSON from [source] using UTF-8 encoding to a value of type [T] using [deserializer].
5655
*
57-
* If [source] is not a [BufferedSource] then called [Source.buffer] for it to create buffered wrapper.
58-
*
5956
* Note that this functions expects that exactly one object would be present in the source
6057
* and throws an exception if there are any dangling bytes after an object.
6158
*
6259
* @throws [SerializationException] if the given JSON input cannot be deserialized to the value of type [T].
6360
* @throws [okio.IOException] If an I/O error occurs and source can't be read from.
6461
*/
6562
@ExperimentalSerializationApi
66-
public fun <T> Json.decodeFromSource(
63+
public fun <T> Json.decodeFromBufferedSource(
6764
deserializer: DeserializationStrategy<T>,
68-
source: Source
65+
source: BufferedSource
6966
): T {
70-
val buffered = if (source is BufferedSource) source else source.buffer()
71-
return decodeByReader(deserializer, OkioSerialReader(buffered))
67+
return decodeByReader(deserializer, OkioSerialReader(source))
7268
}
7369

7470
/**
7571
* Deserializes the contents of given [source] to the value of type [T] using UTF-8 encoding and
7672
* deserializer retrieved from the reified type parameter.
7773
*
78-
* If [source] is not a [BufferedSource] then called [Source.buffer] for it to create buffered wrapper.
79-
*
8074
* Note that this functions expects that exactly one object would be present in the stream
8175
* and throws an exception if there are any dangling bytes after an object.
8276
*
8377
* @throws [SerializationException] if the given JSON input cannot be deserialized to the value of type [T].
8478
* @throws [okio.IOException] If an I/O error occurs and source can't be read from.
8579
*/
8680
@ExperimentalSerializationApi
87-
public inline fun <reified T> Json.decodeFromSource(source: Source): T =
88-
decodeFromSource(serializersModule.serializer(), source)
81+
public inline fun <reified T> Json.decodeFromBufferedSource(source: BufferedSource): T =
82+
decodeFromBufferedSource(serializersModule.serializer(), source)
8983

9084

9185
/**
9286
* Transforms the given [source] into lazily deserialized sequence of elements of type [T] using UTF-8 encoding and [deserializer].
93-
* Unlike [decodeFromSource], [source] is allowed to have more than one element, separated as [format] declares.
94-
*
95-
* If [source] is not a [BufferedSource] then called [Source.buffer] for it to create buffered wrapper.
87+
* Unlike [decodeFromBufferedSource], [source] is allowed to have more than one element, separated as [format] declares.
9688
*
9789
* Elements must all be of type [T].
9890
* Elements are parsed lazily when resulting [Sequence] is evaluated.
9991
* Resulting sequence is tied to the stream and can be evaluated only once.
10092
*
10193
* **Resource caution:** this method neither closes the [source] when the parsing is finished nor provides a method to close it manually.
102-
* It is a caller responsibility to hold a reference to a stream and close it. Moreover, because stream is parsed lazily,
94+
* It is a caller responsibility to hold a reference to a source and close it. Moreover, because source is parsed lazily,
10395
* closing it before returned sequence is evaluated completely will result in [Exception] from decoder.
10496
*
10597
* @throws [SerializationException] if the given JSON input cannot be deserialized to the value of type [T].
10698
* @throws [okio.IOException] If an I/O error occurs and source can't be read from.
10799
*/
108100
@ExperimentalSerializationApi
109-
public fun <T> Json.decodeSourceToSequence(
110-
source: Source,
101+
public fun <T> Json.decodeBufferedSourceToSequence(
102+
source: BufferedSource,
111103
deserializer: DeserializationStrategy<T>,
112104
format: DecodeSequenceMode = DecodeSequenceMode.AUTO_DETECT
113105
): Sequence<T> {
114-
val buffered = if (source is BufferedSource) source else source.buffer()
115-
return decodeToSequenceByReader(OkioSerialReader(buffered), deserializer, format)
106+
return decodeToSequenceByReader(OkioSerialReader(source), deserializer, format)
116107
}
117108

118109
/**
119110
* Transforms the given [source] into lazily deserialized sequence of elements of type [T] using UTF-8 encoding and deserializer retrieved from the reified type parameter.
120-
* Unlike [decodeFromSource], [source] is allowed to have more than one element, separated as [format] declares.
121-
*
122-
* If [source] is not a [BufferedSource] then called [Source.buffer] for it to create buffered wrapper.
111+
* Unlike [decodeFromBufferedSource], [source] is allowed to have more than one element, separated as [format] declares.
123112
*
124113
* Elements must all be of type [T].
125114
* Elements are parsed lazily when resulting [Sequence] is evaluated.
126115
* Resulting sequence is tied to the stream and constrained to be evaluated only once.
127116
*
128117
* **Resource caution:** this method does not close [source] when the parsing is finished neither provides method to close it manually.
129-
* It is a caller responsibility to hold a reference to a stream and close it. Moreover, because stream is parsed lazily,
118+
* It is a caller responsibility to hold a reference to a source and close it. Moreover, because source is parsed lazily,
130119
* closing it before returned sequence is evaluated fully would result in [Exception] from decoder.
131120
*
132121
* @throws [SerializationException] if the given JSON input cannot be deserialized to the value of type [T].
133122
* @throws [okio.IOException] If an I/O error occurs and source can't be read from.
134123
*/
135124
@ExperimentalSerializationApi
136-
public inline fun <reified T> Json.decodeSourceToSequence(
137-
source: Source,
125+
public inline fun <reified T> Json.decodeBufferedSourceToSequence(
126+
source: BufferedSource,
138127
format: DecodeSequenceMode = DecodeSequenceMode.AUTO_DETECT
139-
): Sequence<T> = decodeSourceToSequence(source, serializersModule.serializer(), format)
128+
): Sequence<T> = decodeBufferedSourceToSequence(source, serializersModule.serializer(), format)

formats/json-okio/commonMain/src/kotlinx/serialization/json/okio/internal/OkioJsonStreams.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

5-
@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
5+
@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "CANNOT_OVERRIDE_INVISIBLE_MEMBER")
66

77
package kotlinx.serialization.json.okio.internal
88

@@ -42,7 +42,7 @@ internal class JsonToOkioStreamWriter(private val target: BufferedSink) : JsonWr
4242
}
4343

4444
override fun release() {
45-
target.flush()
45+
// no-op, see https://github.com/Kotlin/kotlinx.serialization/pull/1982#discussion_r915043700
4646
}
4747
}
4848

formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTestBase.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ package kotlinx.serialization.json
66

77
import kotlinx.serialization.*
88
import kotlinx.serialization.json.internal.*
9-
import kotlinx.serialization.json.okio.decodeFromSource
10-
import kotlinx.serialization.json.okio.encodeToSink
9+
import kotlinx.serialization.json.okio.decodeFromBufferedSource
10+
import kotlinx.serialization.json.okio.encodeToBufferedSink
1111
import kotlinx.serialization.modules.EmptySerializersModule
1212
import kotlinx.serialization.modules.SerializersModule
1313
import kotlinx.serialization.test.*
@@ -53,7 +53,7 @@ abstract class JsonTestBase {
5353
}
5454
JsonTestingMode.OKIO_STREAMS -> {
5555
val buffer = Buffer()
56-
encodeToSink(serializer, value, buffer)
56+
encodeToBufferedSink(serializer, value, buffer)
5757
buffer.readUtf8()
5858
}
5959
}
@@ -82,7 +82,7 @@ abstract class JsonTestBase {
8282
JsonTestingMode.OKIO_STREAMS -> {
8383
val buffer = Buffer()
8484
buffer.writeUtf8(source)
85-
decodeFromSource(deserializer, buffer)
85+
decodeFromBufferedSource(deserializer, buffer)
8686
}
8787
}
8888

formats/json/commonMain/src/kotlinx/serialization/json/internal/JsonStreams.kt

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,22 @@ import kotlinx.serialization.*
44
import kotlinx.serialization.json.DecodeSequenceMode
55
import kotlinx.serialization.json.Json
66

7-
/** @suppress */
8-
@InternalSerializationApi
9-
public interface JsonWriter {
10-
public fun writeLong(value: Long)
11-
public fun writeChar(char: Char)
12-
public fun write(text: String)
13-
public fun writeQuoted(text: String)
14-
public fun release()
7+
@PublishedApi
8+
internal interface JsonWriter {
9+
fun writeLong(value: Long)
10+
fun writeChar(char: Char)
11+
fun write(text: String)
12+
fun writeQuoted(text: String)
13+
fun release()
1514
}
1615

17-
/** @suppress */
18-
@InternalSerializationApi
19-
public interface SerialReader {
20-
public fun read(buffer: CharArray, bufferOffset: Int, count: Int): Int
16+
@PublishedApi
17+
internal interface SerialReader {
18+
fun read(buffer: CharArray, bufferOffset: Int, count: Int): Int
2119
}
2220

23-
/** @suppress */
24-
@InternalSerializationApi
25-
public fun <T> Json.encodeByWriter(writer: JsonWriter, serializer: SerializationStrategy<T>, value: T) {
21+
@PublishedApi
22+
internal fun <T> Json.encodeByWriter(writer: JsonWriter, serializer: SerializationStrategy<T>, value: T) {
2623
val encoder = StreamingJsonEncoder(
2724
writer, this,
2825
WriteMode.OBJ,
@@ -31,9 +28,8 @@ public fun <T> Json.encodeByWriter(writer: JsonWriter, serializer: Serialization
3128
encoder.encodeSerializableValue(serializer, value)
3229
}
3330

34-
/** @suppress */
35-
@InternalSerializationApi
36-
public fun <T> Json.decodeByReader(
31+
@PublishedApi
32+
internal fun <T> Json.decodeByReader(
3733
deserializer: DeserializationStrategy<T>,
3834
reader: SerialReader
3935
): T {
@@ -44,10 +40,9 @@ public fun <T> Json.decodeByReader(
4440
return result
4541
}
4642

47-
/** @suppress */
48-
@InternalSerializationApi
43+
@PublishedApi
4944
@ExperimentalSerializationApi
50-
public fun <T> Json.decodeToSequenceByReader(
45+
internal fun <T> Json.decodeToSequenceByReader(
5146
reader: SerialReader,
5247
deserializer: DeserializationStrategy<T>,
5348
format: DecodeSequenceMode = DecodeSequenceMode.AUTO_DETECT
@@ -57,10 +52,9 @@ public fun <T> Json.decodeToSequenceByReader(
5752
return Sequence { iter }.constrainOnce()
5853
}
5954

60-
/** @suppress */
61-
@InternalSerializationApi
55+
@PublishedApi
6256
@ExperimentalSerializationApi
63-
public inline fun <reified T> Json.decodeToSequenceByReader(
57+
internal inline fun <reified T> Json.decodeToSequenceByReader(
6458
reader: SerialReader,
6559
format: DecodeSequenceMode = DecodeSequenceMode.AUTO_DETECT
6660
): Sequence<T> = decodeToSequenceByReader(reader, serializersModule.serializer(), format)

0 commit comments

Comments
 (0)