Coverage Summary for Class: GhostSerializer (com.ghost.serialization.contract)

Class Method, % Branch, % Line, % Instruction, %
GhostSerializer$DefaultImpls 87.5% (7/8) 95% (38/40) 89.9% (152/169)
Total 87.5% (7/8) 95% (38/40) 89.9% (152/169)


 package com.ghost.serialization.contract
 
 import com.ghost.serialization.InternalGhostApi
 import com.ghost.serialization.ghostInternalEncodeAndDrainTo
 import com.ghost.serialization.ghostInternalEncodeWithWriter
 import okio.BufferedSink
 import okio.BufferedSource
 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.GhostJsonWriter
 
 /**
  * Base contract for high-performance JSON serializers.
  *
  * Implementations are typically generated by the Ghost KSP compiler plugin
  * to provide reflection-free serialization and deserialization.
  *
  * # Two-writer design
  *
  * Implementations must provide overloads of `serialize(writer, value)` for
  * [GhostJsonWriter] (streaming I/O), [GhostJsonFlatWriter] (in-memory bytes),
  * and [GhostJsonStringWriter] (in-memory chars).
  */
 @OptIn(InternalGhostApi::class)
 interface GhostSerializer<T> {
 
     /** The unique name of the model in the Ghost registry. */
     val typeName: String
 
     /**
      * Whether this serializer supports resilient parsing (skipping malformed items
      * when used in collections).
      */
     val isResilient: Boolean get() = false
 
     /**
      * Whether this serializer was generated for a `@GhostProtoSerialization` class, applying
      * proto3 canonical JSON mapping rules (quoted int64/uint64, Base64 `bytes`, default-value
      * omission on serialize) rather than plain `@GhostSerialization` rules.
      *
      * Framework integrations that share one dispatch surface for both flavors (e.g. Spring's
      * globally-registered `HttpMessageConverter`) can check this to decide whether to route
      * reads through a proto3-lenient reader — the annotation itself is `BINARY`-retained and
      * not visible via runtime reflection, so this is the supported way to detect it at runtime.
      */
     val isProto: Boolean get() = false
 
     /**
      * Serializes [value] into the provided [sink] using the fast in-memory
      * [GhostJsonFlatWriter] and a single bulk drain. See `Ghost.serialize`
      * for the full rationale.
      */
     fun serialize(sink: BufferedSink, value: T) {
         ghostInternalEncodeAndDrainTo(sink) { writer ->
             serialize(writer, value)
         }
     }
 
     /**
      * Serializes [value] using the streaming [writer] (segmented [okio.Buffer]
      * under the hood). Used by `Ghost.serialize(sink, value)`.
      */
     fun serialize(writer: GhostJsonWriter, value: T)
 
     /**
      * Serializes [value] using the in-memory [writer] (contiguous
      * [com.ghost.serialization.writer.FlatByteArrayWriter] under the hood).
      * Used by `Ghost.encodeToString` / `Ghost.encodeToBytes` to bypass Okio
      * segment overhead on the synchronous in-memory encode path.
      */
     fun serialize(writer: GhostJsonFlatWriter, value: T)
 
     /**
      * Serializes [value] using the in-memory text [writer] (contiguous
      * [com.ghost.serialization.writer.FlatCharArrayWriter] under the hood).
      * Used by `Ghost.encodeToString` to write characters directly.
      */
     fun serialize(writer: GhostJsonStringWriter, value: T) {
         val bytes = ghostInternalEncodeWithWriter { flatWriter ->
             serialize(flatWriter, value)
         }
         writer.rawValue(bytes)
     }
 
     /** Deserializes a new instance of [T] from the [source]. */
     fun deserialize(source: BufferedSource): T {
         val reader = GhostJsonFlatReader(source.readByteArray())
         return deserialize(reader)
     }
 
     /** Deserializes a new instance of [T] using a specialized streaming [reader]. */
     fun deserialize(reader: GhostJsonReader): T
 
     /** Deserializes a new instance of [T] using a specialized flat in-memory [reader]. */
     fun deserialize(reader: GhostJsonFlatReader): T {
         val delegatedReader = GhostJsonReader(reader.rawData).also { 
             it.position = reader.position 
             it.limit = reader.limit
             it.strictMode = reader.strictMode
             it.coerceStringsToNumbers = reader.coerceStringsToNumbers
             it.coerceBooleans = reader.coerceBooleans
             it.maxDepth = reader.maxDepth
             it.maxCollectionSize = reader.maxCollectionSize
         }
         val result = deserialize(delegatedReader)
         reader.position = delegatedReader.position
         reader.nextTokenByte = -1
         return result
     }
 
     /** Deserializes a new instance of [T] using a specialized string [reader]. */
     fun deserialize(reader: GhostJsonStringReader): T {
         val bytes = reader.ensureUtf8Bytes()
         val flatReader = GhostJsonFlatReader(bytes).also {
             it.position = reader.charPositionToBytePosition(reader.position)
             it.limit = bytes.size
             it.strictMode = reader.strictMode
             it.coerceStringsToNumbers = reader.coerceStringsToNumbers
             it.coerceBooleans = reader.coerceBooleans
             it.maxDepth = reader.maxDepth
             it.maxCollectionSize = reader.maxCollectionSize
             it.materializeRawJsonCaptures = true
         }
         val result = deserialize(flatReader)
         reader.position = reader.bytePositionToCharPosition(flatReader.position)
         reader.nextTokenByte = -1
         return result
     }
 
 
     /**
      * Optional warm-up cycle to trigger JIT (Just-In-Time) or ART optimization
      * for critical parsing paths.
      */
     fun warmUp() {}
 }