Get rid of @Suppress("INVISIBLE_REFERENCE") for usage of internal declarations (#2444)

* Introduce additional internal opt-in annotation to hide declarations even more

* Rename JsonWriter and SerialReader to something more internal-ish

* Refactor internal extensions on Json into top-level functions to remove them from completion (because even optable-in declarations are shown in completion for all users)

* Propagate opt-ins to verifyKotlinModule task

Related: https://youtrack.jetbrains.com/issue/KTIJ-27132
diff --git a/buildSrc/src/main/kotlin/Java9Modularity.kt b/buildSrc/src/main/kotlin/Java9Modularity.kt
index 6c0bb52..161b90d 100644
--- a/buildSrc/src/main/kotlin/Java9Modularity.kt
+++ b/buildSrc/src/main/kotlin/Java9Modularity.kt
@@ -131,6 +131,7 @@
                 // To support LV override when set in aggregate builds
                 languageVersion = compileTask.kotlinOptions.languageVersion
                 freeCompilerArgs += listOf("-Xjdk-release=9",  "-Xsuppress-version-warnings")
+                options.optIn.addAll(compileTask.kotlinOptions.options.optIn)
             }
             // work-around for https://youtrack.jetbrains.com/issue/KT-60583
             inputs.files(
diff --git a/core/commonMain/src/kotlinx/serialization/internal/ElementMarker.kt b/core/commonMain/src/kotlinx/serialization/internal/ElementMarker.kt
index fca9026..5e6736d 100644
--- a/core/commonMain/src/kotlinx/serialization/internal/ElementMarker.kt
+++ b/core/commonMain/src/kotlinx/serialization/internal/ElementMarker.kt
@@ -4,13 +4,13 @@
 
 package kotlinx.serialization.internal
 
-import kotlinx.serialization.ExperimentalSerializationApi
+import kotlinx.serialization.*
 import kotlinx.serialization.descriptors.SerialDescriptor
 import kotlinx.serialization.encoding.CompositeDecoder
 
 @OptIn(ExperimentalSerializationApi::class)
-@PublishedApi
-internal class ElementMarker(
+@CoreFriendModuleApi
+public class ElementMarker(
     private val descriptor: SerialDescriptor,
     // Instead of inheritance and virtual function in order to keep cross-module internal modifier via suppresses
     // Can be reworked via public + internal api if necessary
@@ -45,7 +45,7 @@
         }
     }
 
-    fun mark(index: Int) {
+    public fun mark(index: Int) {
         if (index < Long.SIZE_BITS) {
             lowerMarks = lowerMarks or (1L shl index)
         } else {
@@ -53,7 +53,7 @@
         }
     }
 
-    fun nextUnmarkedIndex(): Int {
+    public fun nextUnmarkedIndex(): Int {
         val elementsCount = descriptor.elementsCount
         while (lowerMarks != -1L) {
             val index = lowerMarks.inv().countTrailingZeroBits()
diff --git a/core/commonMain/src/kotlinx/serialization/internal/JsonInternalDependencies.kt b/core/commonMain/src/kotlinx/serialization/internal/JsonInternalDependencies.kt
index d79cb8b..e733827 100644
--- a/core/commonMain/src/kotlinx/serialization/internal/JsonInternalDependencies.kt
+++ b/core/commonMain/src/kotlinx/serialization/internal/JsonInternalDependencies.kt
@@ -1,14 +1,14 @@
 package kotlinx.serialization.internal
 
-import kotlinx.serialization.*
 import kotlinx.serialization.descriptors.*
 
 /*
- * Methods that are required for kotlinx-serialization-json, but are not effectively public
- * and actually represent our own technical debt.
- * This methods are not intended for public use
+ * Methods that are required for kotlinx-serialization-json, but are not effectively public.
+ *
+ * Anything marker with this annotation is not intended for public use.
  */
+@RequiresOptIn(level = RequiresOptIn.Level.ERROR)
+internal annotation class CoreFriendModuleApi
 
-@InternalSerializationApi
-@Deprecated(message = "Should not be used", level = DeprecationLevel.ERROR)
+@CoreFriendModuleApi
 public fun SerialDescriptor.jsonCachedSerialNames(): Set<String> = cachedSerialNames()
diff --git a/core/commonTest/src/kotlinx/serialization/ElementMarkerTest.kt b/core/commonTest/src/kotlinx/serialization/ElementMarkerTest.kt
index a22be3f..3fee587 100644
--- a/core/commonTest/src/kotlinx/serialization/ElementMarkerTest.kt
+++ b/core/commonTest/src/kotlinx/serialization/ElementMarkerTest.kt
@@ -2,10 +2,11 @@
 
 import kotlinx.serialization.descriptors.*
 import kotlinx.serialization.encoding.CompositeDecoder
-import kotlinx.serialization.internal.ElementMarker
+import kotlinx.serialization.internal.*
 import kotlin.test.Test
 import kotlin.test.assertEquals
 
+@OptIn(CoreFriendModuleApi::class)
 class ElementMarkerTest {
     @Test
     fun testNothingWasRead() {
diff --git a/formats/json-okio/build.gradle.kts b/formats/json-okio/build.gradle.kts
index 6d90b77..43859e4 100644
--- a/formats/json-okio/build.gradle.kts
+++ b/formats/json-okio/build.gradle.kts
@@ -15,6 +15,12 @@
 
 kotlin {
     sourceSets {
+        configureEach {
+            languageSettings {
+                optIn("kotlinx.serialization.internal.CoreFriendModuleApi")
+                optIn("kotlinx.serialization.json.internal.JsonFriendModuleApi")
+            }
+        }
         val commonMain by getting {
             dependencies {
                 api(project(":kotlinx-serialization-core"))
@@ -58,4 +64,4 @@
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/formats/json-okio/commonMain/src/kotlinx/serialization/json/okio/OkioStreams.kt b/formats/json-okio/commonMain/src/kotlinx/serialization/json/okio/OkioStreams.kt
index b827806..968f533 100644
--- a/formats/json-okio/commonMain/src/kotlinx/serialization/json/okio/OkioStreams.kt
+++ b/formats/json-okio/commonMain/src/kotlinx/serialization/json/okio/OkioStreams.kt
@@ -2,8 +2,6 @@
  * Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
-@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
-
 package kotlinx.serialization.json.okio
 
 import kotlinx.serialization.*
@@ -29,7 +27,7 @@
 ) {
     val writer = JsonToOkioStreamWriter(sink)
     try {
-        encodeByWriter(writer, serializer, value)
+        encodeByWriter(this, writer, serializer, value)
     } finally {
         writer.release()
     }
@@ -62,7 +60,7 @@
     deserializer: DeserializationStrategy<T>,
     source: BufferedSource
 ): T {
-    return decodeByReader(deserializer, OkioSerialReader(source))
+    return decodeByReader(this, deserializer, OkioSerialReader(source))
 }
 
 /**
@@ -101,7 +99,7 @@
     deserializer: DeserializationStrategy<T>,
     format: DecodeSequenceMode = DecodeSequenceMode.AUTO_DETECT
 ): Sequence<T> {
-    return decodeToSequenceByReader(OkioSerialReader(source), deserializer, format)
+    return decodeToSequenceByReader(this, OkioSerialReader(source), deserializer, format)
 }
 
 /**
diff --git a/formats/json-okio/commonMain/src/kotlinx/serialization/json/okio/internal/OkioJsonStreams.kt b/formats/json-okio/commonMain/src/kotlinx/serialization/json/okio/internal/OkioJsonStreams.kt
index c206678..1de8971 100644
--- a/formats/json-okio/commonMain/src/kotlinx/serialization/json/okio/internal/OkioJsonStreams.kt
+++ b/formats/json-okio/commonMain/src/kotlinx/serialization/json/okio/internal/OkioJsonStreams.kt
@@ -2,16 +2,39 @@
  * Copyright 2017-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
-@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "CANNOT_OVERRIDE_INVISIBLE_MEMBER")
-
 package kotlinx.serialization.json.okio.internal
 
-import kotlinx.serialization.json.internal.ESCAPE_STRINGS
-import kotlinx.serialization.json.internal.JsonWriter
-import kotlinx.serialization.json.internal.SerialReader
+import kotlinx.serialization.json.internal.*
 import okio.*
 
-internal class JsonToOkioStreamWriter(private val sink: BufferedSink) : JsonWriter {
+// Copied from kotlinx/serialization/json/internal/StringOps.kt
+private fun toHexChar(i: Int) : Char {
+    val d = i and 0xf
+    return if (d < 10) (d + '0'.code).toChar()
+    else (d - 10 + 'a'.code).toChar()
+}
+
+// Copied from kotlinx/serialization/json/internal/StringOps.kt
+private val ESCAPE_STRINGS: Array<String?> = arrayOfNulls<String>(93).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['"'.code] = "\\\""
+    this['\\'.code] = "\\\\"
+    this['\t'.code] = "\\t"
+    this['\b'.code] = "\\b"
+    this['\n'.code] = "\\n"
+    this['\r'.code] = "\\r"
+    this[0x0c] = "\\f"
+}
+
+
+
+internal class JsonToOkioStreamWriter(private val sink: BufferedSink) : InternalJsonWriter {
     override fun writeLong(value: Long) {
         write(value.toString())
     }
@@ -54,7 +77,7 @@
 private const val LOW_SURROGATE_HEADER = 0xdc00
 
 
-internal class OkioSerialReader(private val source: BufferedSource): SerialReader {
+internal class OkioSerialReader(private val source: BufferedSource): InternalJsonReader {
     /*
     A sequence of code points is read from UTF-8, some of it can take 2 characters.
     In case the last code point requires 2 characters, and the array is already full, we buffer the second character
diff --git a/formats/json-tests/build.gradle.kts b/formats/json-tests/build.gradle.kts
index 95b9e1c..3c84e29 100644
--- a/formats/json-tests/build.gradle.kts
+++ b/formats/json-tests/build.gradle.kts
@@ -25,6 +25,12 @@
 
 kotlin {
     sourceSets {
+        configureEach {
+            languageSettings {
+                optIn("kotlinx.serialization.internal.CoreFriendModuleApi")
+                optIn("kotlinx.serialization.json.internal.JsonFriendModuleApi")
+            }
+        }
         val commonTest by getting {
             dependencies {
                 api(project(":kotlinx-serialization-json"))
@@ -64,4 +70,4 @@
     tasks.named("wasmD8Test", KotlinJsTest::class) {
         filter.excludePatterns += "kotlinx.serialization.features.EmojiTest"
     }
-}
\ No newline at end of file
+}
diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTestBase.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTestBase.kt
index ebcc3d0..6f3b132 100644
--- a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTestBase.kt
+++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTestBase.kt
@@ -49,7 +49,7 @@
                 encodeViaStream(serializer, value)
             }
             JsonTestingMode.TREE -> {
-                val tree = writeJson(value, serializer)
+                val tree = writeJson(this, value, serializer)
                 encodeToString(tree)
             }
             JsonTestingMode.OKIO_STREAMS -> {
@@ -77,8 +77,8 @@
                 decodeViaStream(deserializer, source)
             }
             JsonTestingMode.TREE -> {
-                val tree = decodeStringToJsonTree(deserializer, source)
-                readJson(tree, deserializer)
+                val tree = decodeStringToJsonTree(this, deserializer, source)
+                readJson(this, tree, deserializer)
             }
             JsonTestingMode.OKIO_STREAMS -> {
                 val buffer = Buffer()
diff --git a/formats/json/api/kotlinx-serialization-json.api b/formats/json/api/kotlinx-serialization-json.api
index e6a2328..bdc6bdf 100644
--- a/formats/json/api/kotlinx-serialization-json.api
+++ b/formats/json/api/kotlinx-serialization-json.api
@@ -383,14 +383,11 @@
 	public static final fun encodeToStream (Lkotlinx/serialization/json/Json;Lkotlinx/serialization/SerializationStrategy;Ljava/lang/Object;Ljava/io/OutputStream;)V
 }
 
-public final class kotlinx/serialization/json/internal/JsonStreamsKt {
-	public static final fun decodeByReader (Lkotlinx/serialization/json/Json;Lkotlinx/serialization/DeserializationStrategy;Lkotlinx/serialization/json/internal/SerialReader;)Ljava/lang/Object;
-	public static final fun decodeToSequenceByReader (Lkotlinx/serialization/json/Json;Lkotlinx/serialization/json/internal/SerialReader;Lkotlinx/serialization/DeserializationStrategy;Lkotlinx/serialization/json/DecodeSequenceMode;)Lkotlin/sequences/Sequence;
-	public static synthetic fun decodeToSequenceByReader$default (Lkotlinx/serialization/json/Json;Lkotlinx/serialization/json/internal/SerialReader;Lkotlinx/serialization/DeserializationStrategy;Lkotlinx/serialization/json/DecodeSequenceMode;ILjava/lang/Object;)Lkotlin/sequences/Sequence;
-	public static final fun encodeByWriter (Lkotlinx/serialization/json/Json;Lkotlinx/serialization/json/internal/JsonWriter;Lkotlinx/serialization/SerializationStrategy;Ljava/lang/Object;)V
+public abstract interface class kotlinx/serialization/json/internal/InternalJsonReader {
+	public abstract fun read ([CII)I
 }
 
-public abstract interface class kotlinx/serialization/json/internal/JsonWriter {
+public abstract interface class kotlinx/serialization/json/internal/InternalJsonWriter {
 	public abstract fun release ()V
 	public abstract fun write (Ljava/lang/String;)V
 	public abstract fun writeChar (C)V
@@ -398,18 +395,17 @@
 	public abstract fun writeQuoted (Ljava/lang/String;)V
 }
 
-public abstract interface class kotlinx/serialization/json/internal/SerialReader {
-	public abstract fun read ([CII)I
+public final class kotlinx/serialization/json/internal/JsonStreamsKt {
+	public static final fun decodeByReader (Lkotlinx/serialization/json/Json;Lkotlinx/serialization/DeserializationStrategy;Lkotlinx/serialization/json/internal/InternalJsonReader;)Ljava/lang/Object;
+	public static final fun decodeToSequenceByReader (Lkotlinx/serialization/json/Json;Lkotlinx/serialization/json/internal/InternalJsonReader;Lkotlinx/serialization/DeserializationStrategy;Lkotlinx/serialization/json/DecodeSequenceMode;)Lkotlin/sequences/Sequence;
+	public static synthetic fun decodeToSequenceByReader$default (Lkotlinx/serialization/json/Json;Lkotlinx/serialization/json/internal/InternalJsonReader;Lkotlinx/serialization/DeserializationStrategy;Lkotlinx/serialization/json/DecodeSequenceMode;ILjava/lang/Object;)Lkotlin/sequences/Sequence;
+	public static final fun encodeByWriter (Lkotlinx/serialization/json/Json;Lkotlinx/serialization/json/internal/InternalJsonWriter;Lkotlinx/serialization/SerializationStrategy;Ljava/lang/Object;)V
 }
 
 public final class kotlinx/serialization/json/internal/StreamingJsonDecoderKt {
 	public static final fun decodeStringToJsonTree (Lkotlinx/serialization/json/Json;Lkotlinx/serialization/DeserializationStrategy;Ljava/lang/String;)Lkotlinx/serialization/json/JsonElement;
 }
 
-public final class kotlinx/serialization/json/internal/StringOpsKt {
-	public static final fun getESCAPE_STRINGS ()[Ljava/lang/String;
-}
-
 public final class kotlinx/serialization/json/internal/TreeJsonDecoderKt {
 	public static final fun readJson (Lkotlinx/serialization/json/Json;Lkotlinx/serialization/json/JsonElement;Lkotlinx/serialization/DeserializationStrategy;)Ljava/lang/Object;
 }
diff --git a/formats/json/build.gradle b/formats/json/build.gradle
index 9b177ac..105c8de 100644
--- a/formats/json/build.gradle
+++ b/formats/json/build.gradle
@@ -24,8 +24,13 @@
 def isNewWasmTargetEnabled = isKotlinVersionAtLeast(rootProject.properties["kotlin_version"], 1, 9, 20)
 
 kotlin {
-
     sourceSets {
+        configureEach {
+            languageSettings {
+                optIn("kotlinx.serialization.internal.CoreFriendModuleApi")
+                optIn("kotlinx.serialization.json.internal.JsonFriendModuleApi")
+            }
+        }
         commonMain {
             dependencies {
                 api project(":kotlinx-serialization-core")
@@ -56,4 +61,4 @@
     if (task.name == 'compileJsWasmMainKotlinMetadata') {
         task.enabled = false
     }
-}
\ No newline at end of file
+}
diff --git a/formats/json/commonMain/src/kotlinx/serialization/json/Json.kt b/formats/json/commonMain/src/kotlinx/serialization/json/Json.kt
index 40dcc23..be7a7f0 100644
--- a/formats/json/commonMain/src/kotlinx/serialization/json/Json.kt
+++ b/formats/json/commonMain/src/kotlinx/serialization/json/Json.kt
@@ -78,7 +78,7 @@
     public final override fun <T> encodeToString(serializer: SerializationStrategy<T>, value: T): String {
         val result = JsonToStringWriter()
         try {
-            encodeByWriter(result, serializer, value)
+            encodeByWriter(this@Json, result, serializer, value)
             return result.toString()
         } finally {
             result.release()
@@ -114,7 +114,7 @@
      * @throws [SerializationException] if the given value cannot be serialized to JSON
      */
     public fun <T> encodeToJsonElement(serializer: SerializationStrategy<T>, value: T): JsonElement {
-        return writeJson(value, serializer)
+        return writeJson(this@Json, value, serializer)
     }
 
     /**
@@ -124,7 +124,7 @@
      * @throws [IllegalArgumentException] if the decoded input cannot be represented as a valid instance of type [T]
      */
     public fun <T> decodeFromJsonElement(deserializer: DeserializationStrategy<T>, element: JsonElement): T {
-        return readJson(element, deserializer)
+        return readJson(this@Json, element, deserializer)
     }
 
     /**
diff --git a/formats/json/commonMain/src/kotlinx/serialization/json/JsonTransformingSerializer.kt b/formats/json/commonMain/src/kotlinx/serialization/json/JsonTransformingSerializer.kt
index 8d1485d..22d87a7 100644
--- a/formats/json/commonMain/src/kotlinx/serialization/json/JsonTransformingSerializer.kt
+++ b/formats/json/commonMain/src/kotlinx/serialization/json/JsonTransformingSerializer.kt
@@ -67,7 +67,7 @@
 
     final override fun serialize(encoder: Encoder, value: T) {
         val output = encoder.asJsonEncoder()
-        var element = output.json.writeJson(value, tSerializer)
+        var element = writeJson(output.json, value, tSerializer)
         element = transformSerialize(element)
         output.encodeJsonElement(element)
     }
diff --git a/formats/json/commonMain/src/kotlinx/serialization/json/internal/Composers.kt b/formats/json/commonMain/src/kotlinx/serialization/json/internal/Composers.kt
index d584155..c1ed8cc 100644
--- a/formats/json/commonMain/src/kotlinx/serialization/json/internal/Composers.kt
+++ b/formats/json/commonMain/src/kotlinx/serialization/json/internal/Composers.kt
@@ -9,11 +9,11 @@
 import kotlinx.serialization.json.*
 import kotlin.jvm.*
 
-internal fun Composer(sb: JsonWriter, json: Json): Composer =
+internal fun Composer(sb: InternalJsonWriter, json: Json): Composer =
     if (json.configuration.prettyPrint) ComposerWithPrettyPrint(sb, json) else Composer(sb)
 
 @OptIn(ExperimentalSerializationApi::class)
-internal open class Composer(@JvmField internal val writer: JsonWriter) {
+internal open class Composer(@JvmField internal val writer: InternalJsonWriter) {
     var writingFirst = true
         protected set
 
@@ -42,7 +42,7 @@
 }
 
 @SuppressAnimalSniffer // Long(Integer).toUnsignedString(long)
-internal class ComposerForUnsignedNumbers(writer: JsonWriter, private val forceQuoting: Boolean) : Composer(writer) {
+internal class ComposerForUnsignedNumbers(writer: InternalJsonWriter, private val forceQuoting: Boolean) : Composer(writer) {
     override fun print(v: Int) {
         if (forceQuoting) printQuoted(v.toUInt().toString()) else print(v.toUInt().toString())
     }
@@ -61,14 +61,14 @@
 }
 
 @SuppressAnimalSniffer
-internal class ComposerForUnquotedLiterals(writer: JsonWriter, private val forceQuoting: Boolean) : Composer(writer) {
+internal class ComposerForUnquotedLiterals(writer: InternalJsonWriter, private val forceQuoting: Boolean) : Composer(writer) {
     override fun printQuoted(value: String) {
         if (forceQuoting) super.printQuoted(value) else super.print(value)
     }
 }
 
 internal class ComposerWithPrettyPrint(
-    writer: JsonWriter,
+    writer: InternalJsonWriter,
     private val json: Json
 ) : Composer(writer) {
     private var level = 0
diff --git a/formats/json/commonMain/src/kotlinx/serialization/json/internal/JsonElementMarker.kt b/formats/json/commonMain/src/kotlinx/serialization/json/internal/JsonElementMarker.kt
index 2535739..85a4624 100644
--- a/formats/json/commonMain/src/kotlinx/serialization/json/internal/JsonElementMarker.kt
+++ b/formats/json/commonMain/src/kotlinx/serialization/json/internal/JsonElementMarker.kt
@@ -2,7 +2,6 @@
  * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
-@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
 
 package kotlinx.serialization.json.internal
 
diff --git a/formats/json/commonMain/src/kotlinx/serialization/json/internal/JsonStreams.kt b/formats/json/commonMain/src/kotlinx/serialization/json/internal/JsonStreams.kt
index 74dbe45..05f025c 100644
--- a/formats/json/commonMain/src/kotlinx/serialization/json/internal/JsonStreams.kt
+++ b/formats/json/commonMain/src/kotlinx/serialization/json/internal/JsonStreams.kt
@@ -4,38 +4,42 @@
 import kotlinx.serialization.json.DecodeSequenceMode
 import kotlinx.serialization.json.Json
 
-@PublishedApi
-internal interface JsonWriter {
-    fun writeLong(value: Long)
-    fun writeChar(char: Char)
-    fun write(text: String)
-    fun writeQuoted(text: String)
-    fun release()
+@RequiresOptIn(level = RequiresOptIn.Level.ERROR)
+internal annotation class JsonFriendModuleApi
+
+@JsonFriendModuleApi
+public interface InternalJsonWriter {
+    public fun writeLong(value: Long)
+    public fun writeChar(char: Char)
+    public fun write(text: String)
+    public fun writeQuoted(text: String)
+    public fun release()
 }
 
-@PublishedApi
-internal interface SerialReader {
-    fun read(buffer: CharArray, bufferOffset: Int, count: Int): Int
+@JsonFriendModuleApi
+public interface InternalJsonReader {
+    public fun read(buffer: CharArray, bufferOffset: Int, count: Int): Int
 }
 
-@PublishedApi
-internal fun <T> Json.encodeByWriter(writer: JsonWriter, serializer: SerializationStrategy<T>, value: T) {
+@JsonFriendModuleApi
+public fun <T> encodeByWriter(json: Json, writer: InternalJsonWriter, serializer: SerializationStrategy<T>, value: T) {
     val encoder = StreamingJsonEncoder(
-        writer, this,
+        writer, json,
         WriteMode.OBJ,
-        arrayOfNulls(WriteMode.values().size)
+        arrayOfNulls(WriteMode.entries.size)
     )
     encoder.encodeSerializableValue(serializer, value)
 }
 
-@PublishedApi
-internal fun <T> Json.decodeByReader(
+@JsonFriendModuleApi
+public fun <T> decodeByReader(
+    json: Json,
     deserializer: DeserializationStrategy<T>,
-    reader: SerialReader
+    reader: InternalJsonReader
 ): T {
     val lexer = ReaderJsonLexer(reader)
     try {
-        val input = StreamingJsonDecoder(this, WriteMode.OBJ, lexer, deserializer.descriptor, null)
+        val input = StreamingJsonDecoder(json, WriteMode.OBJ, lexer, deserializer.descriptor, null)
         val result = input.decodeSerializableValue(deserializer)
         lexer.expectEof()
         return result
@@ -44,21 +48,23 @@
     }
 }
 
-@PublishedApi
+@JsonFriendModuleApi
 @ExperimentalSerializationApi
-internal fun <T> Json.decodeToSequenceByReader(
-    reader: SerialReader,
+public fun <T> decodeToSequenceByReader(
+    json: Json,
+    reader: InternalJsonReader,
     deserializer: DeserializationStrategy<T>,
     format: DecodeSequenceMode = DecodeSequenceMode.AUTO_DETECT
 ): Sequence<T> {
     val lexer = ReaderJsonLexer(reader, CharArray(BATCH_SIZE)) // Unpooled buffer due to lazy nature of sequence
-    val iter = JsonIterator(format, this, lexer, deserializer)
+    val iter = JsonIterator(format, json, lexer, deserializer)
     return Sequence { iter }.constrainOnce()
 }
 
-@PublishedApi
+@JsonFriendModuleApi
 @ExperimentalSerializationApi
-internal inline fun <reified T> Json.decodeToSequenceByReader(
-    reader: SerialReader,
+public inline fun <reified T> decodeToSequenceByReader(
+    json: Json,
+    reader: InternalJsonReader,
     format: DecodeSequenceMode = DecodeSequenceMode.AUTO_DETECT
-): Sequence<T> = decodeToSequenceByReader(reader, serializersModule.serializer(), format)
+): Sequence<T> = decodeToSequenceByReader(json, reader, json.serializersModule.serializer(), format)
diff --git a/formats/json/commonMain/src/kotlinx/serialization/json/internal/JsonToStringWriter.kt b/formats/json/commonMain/src/kotlinx/serialization/json/internal/JsonToStringWriter.kt
index 4df35de..a6a123c 100644
--- a/formats/json/commonMain/src/kotlinx/serialization/json/internal/JsonToStringWriter.kt
+++ b/formats/json/commonMain/src/kotlinx/serialization/json/internal/JsonToStringWriter.kt
@@ -1,6 +1,6 @@
 package kotlinx.serialization.json.internal
 
-internal expect class JsonToStringWriter constructor() : JsonWriter {
+internal expect class JsonToStringWriter constructor() : InternalJsonWriter {
     override fun writeChar(char: Char)
     override fun writeLong(value: Long)
     override fun write(text: String)
diff --git a/formats/json/commonMain/src/kotlinx/serialization/json/internal/StreamingJsonDecoder.kt b/formats/json/commonMain/src/kotlinx/serialization/json/internal/StreamingJsonDecoder.kt
index ce93009..4e373f1 100644
--- a/formats/json/commonMain/src/kotlinx/serialization/json/internal/StreamingJsonDecoder.kt
+++ b/formats/json/commonMain/src/kotlinx/serialization/json/internal/StreamingJsonDecoder.kt
@@ -49,7 +49,6 @@
 
     override fun decodeJsonElement(): JsonElement = JsonTreeReader(json.configuration, lexer).read()
 
-    @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
     override fun <T> decodeSerializableValue(deserializer: DeserializationStrategy<T>): T {
         try {
             /*
@@ -350,13 +349,14 @@
     }
 }
 
-@InternalSerializationApi
-public fun <T> Json.decodeStringToJsonTree(
+@JsonFriendModuleApi // used in json-tests
+public fun <T> decodeStringToJsonTree(
+    json: Json,
     deserializer: DeserializationStrategy<T>,
     source: String
 ): JsonElement {
     val lexer = StringJsonLexer(source)
-    val input = StreamingJsonDecoder(this, WriteMode.OBJ, lexer, deserializer.descriptor, null)
+    val input = StreamingJsonDecoder(json, WriteMode.OBJ, lexer, deserializer.descriptor, null)
     val tree = input.decodeJsonElement()
     lexer.expectEof()
     return tree
diff --git a/formats/json/commonMain/src/kotlinx/serialization/json/internal/StreamingJsonEncoder.kt b/formats/json/commonMain/src/kotlinx/serialization/json/internal/StreamingJsonEncoder.kt
index c6f76cb..4f7b1ec 100644
--- a/formats/json/commonMain/src/kotlinx/serialization/json/internal/StreamingJsonEncoder.kt
+++ b/formats/json/commonMain/src/kotlinx/serialization/json/internal/StreamingJsonEncoder.kt
@@ -10,7 +10,6 @@
 import kotlinx.serialization.encoding.*
 import kotlinx.serialization.json.*
 import kotlinx.serialization.modules.*
-import kotlin.native.concurrent.*
 
 private val unsignedNumberDescriptors = setOf(
     UInt.serializer().descriptor,
@@ -34,7 +33,7 @@
 ) : JsonEncoder, AbstractEncoder() {
 
     internal constructor(
-        output: JsonWriter, json: Json, mode: WriteMode,
+        output: InternalJsonWriter, json: Json, mode: WriteMode,
         modeReuseCache: Array<JsonEncoder?>
     ) : this(Composer(output, json), json, mode, modeReuseCache)
 
@@ -164,7 +163,7 @@
             else                        -> super.encodeInline(descriptor)
         }
 
-    private inline fun <reified T: Composer> composerAs(composerCreator: (writer: JsonWriter, forceQuoting: Boolean) -> T): T {
+    private inline fun <reified T: Composer> composerAs(composerCreator: (writer: InternalJsonWriter, forceQuoting: Boolean) -> T): T {
         // If we're inside encodeInline().encodeSerializableValue, we should preserve the forceQuoting state
         // inside the composer, but not in the encoder (otherwise we'll get into `if (forceQuoting) encodeString(value.toString())` part
         // and unsigned numbers would be encoded incorrectly)
diff --git a/formats/json/commonMain/src/kotlinx/serialization/json/internal/StringOps.kt b/formats/json/commonMain/src/kotlinx/serialization/json/internal/StringOps.kt
index f488d90..ed76ba0 100644
--- a/formats/json/commonMain/src/kotlinx/serialization/json/internal/StringOps.kt
+++ b/formats/json/commonMain/src/kotlinx/serialization/json/internal/StringOps.kt
@@ -12,7 +12,6 @@
     else (d - 10 + 'a'.code).toChar()
 }
 
-@PublishedApi
 internal val ESCAPE_STRINGS: Array<String?> = arrayOfNulls<String>(93).apply {
     for (c in 0..0x1f) {
         val c1 = toHexChar(c shr 12)
@@ -68,4 +67,4 @@
     this.equals("true", ignoreCase = true) -> true
     this.equals("false", ignoreCase = true) -> false
     else -> null
-}
\ No newline at end of file
+}
diff --git a/formats/json/commonMain/src/kotlinx/serialization/json/internal/TreeJsonDecoder.kt b/formats/json/commonMain/src/kotlinx/serialization/json/internal/TreeJsonDecoder.kt
index 4b355f6..aedfb95 100644
--- a/formats/json/commonMain/src/kotlinx/serialization/json/internal/TreeJsonDecoder.kt
+++ b/formats/json/commonMain/src/kotlinx/serialization/json/internal/TreeJsonDecoder.kt
@@ -15,12 +15,12 @@
 import kotlinx.serialization.modules.*
 import kotlin.jvm.*
 
-@InternalSerializationApi
-public fun <T> Json.readJson(element: JsonElement, deserializer: DeserializationStrategy<T>): T {
+@JsonFriendModuleApi
+public fun <T> readJson(json: Json, element: JsonElement, deserializer: DeserializationStrategy<T>): T {
     val input = when (element) {
-        is JsonObject -> JsonTreeDecoder(this, element)
-        is JsonArray -> JsonTreeListDecoder(this, element)
-        is JsonLiteral, JsonNull -> JsonPrimitiveDecoder(this, element as JsonPrimitive)
+        is JsonObject -> JsonTreeDecoder(json, element)
+        is JsonArray -> JsonTreeListDecoder(json, element)
+        is JsonLiteral, JsonNull -> JsonPrimitiveDecoder(json, element as JsonPrimitive)
     }
     return input.decodeSerializableValue(deserializer)
 }
diff --git a/formats/json/commonMain/src/kotlinx/serialization/json/internal/TreeJsonEncoder.kt b/formats/json/commonMain/src/kotlinx/serialization/json/internal/TreeJsonEncoder.kt
index e42d425..5e3c808 100644
--- a/formats/json/commonMain/src/kotlinx/serialization/json/internal/TreeJsonEncoder.kt
+++ b/formats/json/commonMain/src/kotlinx/serialization/json/internal/TreeJsonEncoder.kt
@@ -14,10 +14,10 @@
 import kotlin.collections.set
 import kotlin.jvm.*
 
-@InternalSerializationApi
-public fun <T> Json.writeJson(value: T, serializer: SerializationStrategy<T>): JsonElement {
+@JsonFriendModuleApi
+public fun <T> writeJson(json: Json, value: T, serializer: SerializationStrategy<T>): JsonElement {
     lateinit var result: JsonElement
-    val encoder = JsonTreeEncoder(this) { result = it }
+    val encoder = JsonTreeEncoder(json) { result = it }
     encoder.encodeSerializableValue(serializer, value)
     return result
 }
diff --git a/formats/json/commonMain/src/kotlinx/serialization/json/internal/lexer/ReaderJsonLexer.kt b/formats/json/commonMain/src/kotlinx/serialization/json/internal/lexer/ReaderJsonLexer.kt
index 3c785f8..24e5b47 100644
--- a/formats/json/commonMain/src/kotlinx/serialization/json/internal/lexer/ReaderJsonLexer.kt
+++ b/formats/json/commonMain/src/kotlinx/serialization/json/internal/lexer/ReaderJsonLexer.kt
@@ -2,8 +2,6 @@
  * Copyright 2017-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
  */
 
-@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
-
 package kotlinx.serialization.json.internal
 
 internal const val BATCH_SIZE: Int = 16 * 1024
@@ -13,7 +11,7 @@
  * For some reason this hand-rolled implementation is faster than
  * fun ArrayAsSequence(s: CharArray): CharSequence = java.nio.CharBuffer.wrap(s, 0, length)
  */
-internal class ArrayAsSequence(private val buffer: CharArray) : CharSequence {
+internal class ArrayAsSequence(internal val buffer: CharArray) : CharSequence {
     override var length: Int = buffer.size
 
     override fun get(index: Int): Char = buffer[index]
@@ -35,7 +33,7 @@
 }
 
 internal class ReaderJsonLexer(
-    private val reader: SerialReader,
+    private val reader: InternalJsonReader,
     private val buffer: CharArray = CharArrayPoolBatchSize.take()
 ) : AbstractJsonLexer() {
     private var threshold: Int = DEFAULT_THRESHOLD // chars
diff --git a/formats/json/jsWasmMain/src/kotlinx/serialization/json/internal/JsonToStringWriterJsWasm.kt b/formats/json/jsWasmMain/src/kotlinx/serialization/json/internal/JsonToStringWriterJsWasm.kt
index 806a1d8..387ed7e 100644
--- a/formats/json/jsWasmMain/src/kotlinx/serialization/json/internal/JsonToStringWriterJsWasm.kt
+++ b/formats/json/jsWasmMain/src/kotlinx/serialization/json/internal/JsonToStringWriterJsWasm.kt
@@ -1,6 +1,6 @@
 package kotlinx.serialization.json.internal
 
-internal actual open class JsonToStringWriter actual constructor(): JsonWriter {
+internal actual open class JsonToStringWriter actual constructor(): InternalJsonWriter {
     private val sb = StringBuilder(128)
 
     actual override fun writeLong(value: Long) {
diff --git a/formats/json/jvmMain/src/kotlinx/serialization/json/JvmStreams.kt b/formats/json/jvmMain/src/kotlinx/serialization/json/JvmStreams.kt
index 4af1045..329e309 100644
--- a/formats/json/jvmMain/src/kotlinx/serialization/json/JvmStreams.kt
+++ b/formats/json/jvmMain/src/kotlinx/serialization/json/JvmStreams.kt
@@ -22,7 +22,7 @@
 ) {
     val writer = JsonToJavaStreamWriter(stream)
     try {
-        encodeByWriter(writer, serializer, value)
+        encodeByWriter(this, writer, serializer, value)
     } finally {
         writer.release()
     }
@@ -58,7 +58,7 @@
 ): T {
     val reader = JavaStreamSerialReader(stream)
     try {
-        return decodeByReader(deserializer, reader)
+        return decodeByReader(this, deserializer, reader)
     } finally {
         reader.release()
     }
@@ -102,7 +102,7 @@
     deserializer: DeserializationStrategy<T>,
     format: DecodeSequenceMode = DecodeSequenceMode.AUTO_DETECT
 ): Sequence<T> {
-    return decodeToSequenceByReader(JavaStreamSerialReader(stream), deserializer, format)
+    return decodeToSequenceByReader(this, JavaStreamSerialReader(stream), deserializer, format)
 }
 
 /**
diff --git a/formats/json/jvmMain/src/kotlinx/serialization/json/internal/JsonToStringWriter.kt b/formats/json/jvmMain/src/kotlinx/serialization/json/internal/JsonToStringWriter.kt
index e11c21c..5666724 100644
--- a/formats/json/jvmMain/src/kotlinx/serialization/json/internal/JsonToStringWriter.kt
+++ b/formats/json/jvmMain/src/kotlinx/serialization/json/internal/JsonToStringWriter.kt
@@ -25,7 +25,7 @@
  * 3) We pool char arrays in order to save excess resizes, allocations
  *    and nulls-out of arrays.
  */
-internal actual class JsonToStringWriter : JsonWriter {
+internal actual class JsonToStringWriter : InternalJsonWriter {
     private var array: CharArray = CharArrayPool.take()
     private var size = 0
 
diff --git a/formats/json/jvmMain/src/kotlinx/serialization/json/internal/JvmJsonStreams.kt b/formats/json/jvmMain/src/kotlinx/serialization/json/internal/JvmJsonStreams.kt
index 274dd4d..e8e0d9a 100644
--- a/formats/json/jvmMain/src/kotlinx/serialization/json/internal/JvmJsonStreams.kt
+++ b/formats/json/jvmMain/src/kotlinx/serialization/json/internal/JvmJsonStreams.kt
@@ -3,7 +3,7 @@
 import java.io.InputStream
 import java.io.OutputStream
 
-internal class JsonToJavaStreamWriter(private val stream: OutputStream) : JsonWriter {
+internal class JsonToJavaStreamWriter(private val stream: OutputStream) : InternalJsonWriter {
     private val buffer = ByteArrayPool.take()
     private var charArray = CharArrayPool.take()
     private var indexInBuffer: Int = 0
@@ -253,7 +253,7 @@
     }
 }
 
-internal class JavaStreamSerialReader(stream: InputStream) : SerialReader {
+internal class JavaStreamSerialReader(stream: InputStream) : InternalJsonReader {
     // NB: not closed on purpose, it is the responsibility of the caller
     private val reader = CharsetReader(stream, Charsets.UTF_8)
 
diff --git a/formats/json/nativeMain/src/kotlinx/serialization/json/internal/JsonToStringWriter.kt b/formats/json/nativeMain/src/kotlinx/serialization/json/internal/JsonToStringWriter.kt
index d996fc3..137f3bc 100644
--- a/formats/json/nativeMain/src/kotlinx/serialization/json/internal/JsonToStringWriter.kt
+++ b/formats/json/nativeMain/src/kotlinx/serialization/json/internal/JsonToStringWriter.kt
@@ -1,6 +1,6 @@
 package kotlinx.serialization.json.internal
 
-internal actual open class JsonToStringWriter actual constructor(): JsonWriter {
+internal actual open class JsonToStringWriter actual constructor(): InternalJsonWriter {
     private val sb = StringBuilder(128)
 
     actual override fun writeLong(value: Long) {
diff --git a/formats/protobuf/build.gradle b/formats/protobuf/build.gradle
index c2183b2..9f93b18 100644
--- a/formats/protobuf/build.gradle
+++ b/formats/protobuf/build.gradle
@@ -21,8 +21,11 @@
 }
 
 kotlin {
-
     sourceSets {
+        configureEach {
+            languageSettings.optIn("kotlinx.serialization.internal.CoreFriendModuleApi")
+        }
+
         commonMain {
             dependencies {
                 api project(":kotlinx-serialization-core")
diff --git a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufDecoding.kt b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufDecoding.kt
index d2a28b5..861e2bf 100644
--- a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufDecoding.kt
+++ b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufDecoding.kt
@@ -3,7 +3,7 @@
  */
 
 @file:OptIn(ExperimentalSerializationApi::class)
-@file:Suppress("UNCHECKED_CAST", "INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
+@file:Suppress("UNCHECKED_CAST")
 
 package kotlinx.serialization.protobuf.internal
 
@@ -213,7 +213,7 @@
         val mapEntrySerial =
             kotlinx.serialization.builtins.MapEntrySerializer(serializer.keySerializer, serializer.valueSerializer)
         val oldSet = (previousValue as? Map<Any?, Any?>)?.entries
-        val setOfEntries = LinkedHashSetSerializer(mapEntrySerial).merge(this, oldSet)
+        val setOfEntries = (SetSerializer(mapEntrySerial) as AbstractCollectionSerializer<Map.Entry<Any?, Any?>, Set<Map.Entry<Any?, Any?>>, *>).merge(this, oldSet)
         return setOfEntries.associateBy({ it.key }, { it.value }) as T
     }