diff --git a/formats/json-tests/jvmTest/src/kotlinx/serialization/features/JsonLazySequenceTest.kt b/formats/json-tests/jvmTest/src/kotlinx/serialization/features/JsonLazySequenceTest.kt index f6d13f702..23887660d 100644 --- a/formats/json-tests/jvmTest/src/kotlinx/serialization/features/JsonLazySequenceTest.kt +++ b/formats/json-tests/jvmTest/src/kotlinx/serialization/features/JsonLazySequenceTest.kt @@ -83,6 +83,7 @@ class JsonLazySequenceTest { iter.assertNext(StringData("b")) iter.assertNext(StringData("c")) assertFalse(iter.hasNext()) + assertFalse(iter.hasNext()) // Subsequent calls to .hasNext() should not throw EOF or anything assertFailsWithMessage("EOF") { iter.next() } @@ -186,4 +187,11 @@ class JsonLazySequenceTest { assertEquals(inputList, json.decodeToSequence(paddedWs.asInputStream(), StringData.serializer(), DecodeSequenceMode.ARRAY_WRAPPED).toList()) } + @Test + fun testToIteratorAndBack() = withInputs { ins -> + val iterator = Json.decodeToSequence(ins, StringData.serializer()).iterator() + val values = iterator.asSequence().take(3).toList() + assertEquals(inputList, values) + assertFalse(iterator.hasNext()) + } } diff --git a/formats/json/commonMain/src/kotlinx/serialization/json/Json.kt b/formats/json/commonMain/src/kotlinx/serialization/json/Json.kt index d73bb39d1..6f5ba9fb2 100644 --- a/formats/json/commonMain/src/kotlinx/serialization/json/Json.kt +++ b/formats/json/commonMain/src/kotlinx/serialization/json/Json.kt @@ -169,7 +169,7 @@ public enum class DecodeSequenceMode { /** * Declares that parser itself should select between [WHITESPACE_SEPARATED] and [ARRAY_WRAPPED] modes. - * The selection is performed by looking on the first meaningful character of the stream. + * The selection is performed by looking at the first meaningful character of the stream. * * In most cases, auto-detection is sufficient to correctly parse an input. * If the input is _whitespace-separated stream of the arrays_, parser could select an incorrect mode, diff --git a/formats/json/commonMain/src/kotlinx/serialization/json/internal/JsonIterator.kt b/formats/json/commonMain/src/kotlinx/serialization/json/internal/JsonIterator.kt index 3929c840a..00f36b2b0 100644 --- a/formats/json/commonMain/src/kotlinx/serialization/json/internal/JsonIterator.kt +++ b/formats/json/commonMain/src/kotlinx/serialization/json/internal/JsonIterator.kt @@ -68,6 +68,7 @@ private class JsonIteratorArrayWrapped( private val deserializer: DeserializationStrategy ) : Iterator { private var first = true + private var finished = false override fun next(): T { if (first) { @@ -83,7 +84,9 @@ private class JsonIteratorArrayWrapped( * Note: if array separator (comma) is missing, hasNext() returns true, but next() throws an exception. */ override fun hasNext(): Boolean { + if (finished) return false if (lexer.peekNextToken() == TC_END_LIST) { + finished = true lexer.consumeNextToken(TC_END_LIST) if (lexer.isNotEof()) { if (lexer.peekNextToken() == TC_BEGIN_LIST) lexer.fail("There is a start of the new array after the one parsed to sequence. " + @@ -93,7 +96,7 @@ private class JsonIteratorArrayWrapped( } return false } - if (!lexer.isNotEof()) lexer.fail(TC_END_LIST) + if (!lexer.isNotEof() && !finished) lexer.fail(TC_END_LIST) return true } } diff --git a/formats/json/commonMain/src/kotlinx/serialization/json/internal/lexer/JsonLexer.kt b/formats/json/commonMain/src/kotlinx/serialization/json/internal/lexer/JsonLexer.kt index fa4772c7d..2881fd79b 100644 --- a/formats/json/commonMain/src/kotlinx/serialization/json/internal/lexer/JsonLexer.kt +++ b/formats/json/commonMain/src/kotlinx/serialization/json/internal/lexer/JsonLexer.kt @@ -30,6 +30,9 @@ internal class ArrayAsSequence(private val buffer: CharArray) : CharSequence { fun trim(newSize: Int) { length = minOf(buffer.size, newSize) } + + // source.toString() is used in JsonDecodingException + override fun toString(): String = substring(0, length) } internal class ReaderJsonLexer(