Coverage Summary for Class: Ghost_jvmKt (com.ghost.serialization)

Class Method, % Branch, % Line, % Instruction, %
Ghost_jvmKt 94.4% (17/18) 68.8% (22/32) 84.7% (100/118) 98% (295/301)
Ghost_jvmKt$discoverRegistries$$inlined$Iterable$1 0% (0/2)
Ghost_jvmKt$discoverRegistries$1$1 100% (3/3) 63.9% (23/36) 86% (37/43) 93.3% (168/180)
Total 87% (20/23) 66.2% (45/68) 85.1% (137/161) 96.3% (463/481)


 @file:OptIn(InternalGhostApi::class)
 
 package com.ghost.serialization
 
 import com.ghost.serialization.contract.GhostRegistry
 import com.ghost.serialization.parser.GhostJsonReader
 import com.ghost.serialization.parser.GhostJsonFlatReader
 import com.ghost.serialization.parser.GhostJsonStringReader
 import com.ghost.serialization.writer.GhostJsonFlatWriter
 import com.ghost.serialization.writer.GhostJsonStringWriter
 import com.ghost.serialization.writer.WriterSinkPair
 import com.ghost.serialization.writer.FlatCharArrayWriter
 import okio.BufferedSource
 import java.util.ServiceLoader
 import java.util.concurrent.ConcurrentHashMap
 
 private val readerPool = ThreadLocal<GhostJsonReader>()
 private val flatReaderPool = ThreadLocal<GhostJsonFlatReader>()
 private val stringReaderPool = ThreadLocal<GhostJsonStringReader>()
 private val sourceReaderPool = ThreadLocal<GhostJsonReader>()
 @PublishedApi
 internal val writerPool = ThreadLocal<WriterSinkPair>()
 
 actual fun <T> runSynchronized(lock: Any, block: () -> T): T = synchronized(lock, block)
 
 actual fun <K, V> createAtomicMap(): MutableMap<K, V> = ConcurrentHashMap()
 
 /**
  * Acquires the per-thread [WriterSinkPair], resets it for a fresh encode,
  * and returns it. The pair survives across calls so the underlying
  * [com.ghost.serialization.writer.FlatByteArrayWriter] grows once and stays warm.
  */
 @PublishedApi
 internal fun acquireFlatWriterPair(): WriterSinkPair {
     val pair = writerPool.get()
         ?: WriterSinkPair()
             .also { writerPool.set(it) }
     
     pair.writer.reset()
     pair.byteWriter.reset()
     return pair
 }
 
 @PublishedApi
 internal class WriterStringPair {
     val charWriter = FlatCharArrayWriter()
     val writer = GhostJsonStringWriter(charWriter)
 }
 
 @PublishedApi
 internal val stringWriterPool = ThreadLocal<WriterStringPair>()
 
 @PublishedApi
 internal fun acquireStringWriterPair(): WriterStringPair {
     val pair = stringWriterPool.get()
         ?: WriterStringPair().also { stringWriterPool.set(it) }
     pair.writer.reset()
     pair.charWriter.reset()
     return pair
 }
 
 @InternalGhostApi
 actual inline fun ghostInternalEncodeToString(
     crossinline block: (GhostJsonStringWriter) -> Unit
 ): String {
     val pair = acquireStringWriterPair()
     block(pair.writer)
     val result = String(
         pair.charWriter.array,
         0,
         pair.charWriter.size
     )
     pair.charWriter.reset()
     return result
 }
 
 @InternalGhostApi
 actual inline fun ghostInternalEncodeWithWriter(
     crossinline block: (GhostJsonFlatWriter) -> Unit
 ): ByteArray {
     val pair = acquireFlatWriterPair()
     block(pair.writer)
     val result = pair.byteWriter.toByteArray()
     pair.byteWriter.reset()
     return result
 }
 
 @InternalGhostApi
 actual inline fun ghostInternalEncodeAndDiscard(
     crossinline block: (GhostJsonFlatWriter) -> Unit
 ) {
     val pair = acquireFlatWriterPair()
     block(pair.writer)
     pair.byteWriter.reset()
 }
 
 @InternalGhostApi
 actual inline fun ghostInternalEncodeAndDrainTo(
     sink: okio.BufferedSink,
     crossinline block: (GhostJsonFlatWriter) -> Unit
 ) {
     val pair = acquireFlatWriterPair()
     block(pair.writer)
     sink.write(
         pair.byteWriter.array,
         0,
         pair.byteWriter.size
     )
     pair.byteWriter.reset()
 }
 
 actual fun discoverRegistries(): Iterable<GhostRegistry> = Iterable {
     object : Iterator<GhostRegistry> {
         private var fastRegistries: MutableList<GhostRegistry>? = null
         private var fastIterator: Iterator<GhostRegistry>? = null
         private var fastChecked = false
         private var slow: Iterator<GhostRegistry>? = null
 
         override fun hasNext(): Boolean {
             if (!fastChecked) {
                 fastChecked = true
                 val names = listOf(
                     Ghost.DEFAULT_REGISTRY_NAME,
                     Ghost.TEST_REGISTRY_NAME
                 )
                 fastRegistries = names.mapNotNull { name ->
                     runCatching {
                         Class.forName(name)
                             .getField(Ghost.INSTANCE_FIELD)
                             .get(null) as GhostRegistry
                     }.getOrNull()
                 }.toMutableList()
                 fastIterator = fastRegistries?.iterator()
             }
             
             if (fastIterator?.hasNext() == true) return true
 
             if (slow == null) {
                 slow = runCatching {
                     ServiceLoader
                         .load(GhostRegistry::class.java)
                         .iterator()
                 }
                     .getOrDefault(
                         emptyList<GhostRegistry>()
                             .iterator()
                     )
             }
             return slow!!.hasNext()
         }
 
         override fun next(): GhostRegistry {
             if (!hasNext()) throw NoSuchElementException()
             if (fastIterator?.hasNext() == true) return fastIterator!!.next()
             return slow!!.next()
         }
     }
 }
 
 actual fun <T> ghostInternalUseReader(
     bytes: ByteArray,
     block: (GhostJsonReader) -> T
 ): T {
     val reader = readerPool.get()
         ?: GhostJsonReader(bytes)
             .also { readerPool.set(it) }
 
     reader.reset(bytes)
     return block(reader)
 }
 
 actual fun <T> ghostInternalUseFlatReader(
     bytes: ByteArray,
     limit: Int,
     block: (GhostJsonFlatReader) -> T
 ): T {
     val reader = flatReaderPool.get()
         ?: GhostJsonFlatReader(bytes)
             .also { flatReaderPool.set(it) }
 
     reader.reset(bytes, limit)
     return block(reader)
 }
 
 actual fun <T> ghostInternalUseSource(
     source: BufferedSource,
     block: (GhostJsonReader) -> T
 ): T {
     // Separate pool from readerPool to prevent re-entrance corruption if the
     // same thread nests a ByteArray read inside a streaming read.
     val reader = sourceReaderPool.get()
         ?: GhostJsonReader(source)
             .also { sourceReaderPool.set(it) }
 
     // data in 8 KB segments on demand instead of loading the entire payload.
     reader.reset(source)
     return block(reader)
 }
 
 actual fun <T> ghostInternalUseStringReader(
     json: String,
     block: (GhostJsonStringReader) -> T
 ): T {
     val reader = stringReaderPool.get()
         ?: GhostJsonStringReader(json)
             .also { stringReaderPool.set(it) }
 
     reader.reset(json)
     return block(reader)
 }