Coverage Summary for Class: GhostProtobuf (com.ghost.protobuf)
| Class |
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
| GhostProtobuf |
62.5%
(5/8)
|
33.3%
(2/6)
|
34.6%
(9/26)
|
41.2%
(61/148)
|
| GhostProtobuf$deserialize$$inlined$deserialize$1 |
0%
(0/1)
|
|
0%
(0/1)
|
0%
(0/4)
|
| GhostProtobuf$deserialize$$inlined$resolveSerializer$1 |
0%
(0/1)
|
|
0%
(0/1)
|
0%
(0/4)
|
| GhostProtobuf$deserialize$$inlined$resolveSerializer$2 |
0%
(0/1)
|
|
0%
(0/1)
|
0%
(0/4)
|
| GhostProtobuf$deserialize$$inlined$resolveSerializer$3 |
0%
(0/1)
|
|
0%
(0/1)
|
0%
(0/4)
|
| GhostProtobuf$encodeToBytes$$inlined$encodeToBytes$1 |
0%
(0/1)
|
|
0%
(0/1)
|
0%
(0/4)
|
| GhostProtobuf$encodeToString$$inlined$encodeToString$1 |
0%
(0/1)
|
|
0%
(0/1)
|
0%
(0/4)
|
| Total |
35.7%
(5/14)
|
33.3%
(2/6)
|
28.1%
(9/32)
|
35.5%
(61/172)
|
@file:OptIn(InternalGhostApi::class)
package com.ghost.protobuf
import com.ghost.serialization.Ghost
import com.ghost.serialization.contract.GhostSerializer
import com.ghost.serialization.parser.GhostProtoJsonFlatReader
import com.ghost.serialization.InternalGhostApi
import com.ghost.serialization.acquireScratchBuffer
import com.ghost.serialization.releaseScratchBuffer
import okio.BufferedSource
import kotlin.reflect.KClass
object GhostProtobuf {
inline fun <reified T : Any> deserialize(bytes: ByteArray): T {
val reader = GhostProtoJsonFlatReader(bytes)
val serializer = Ghost.resolveSerializer<T>()
return serializer.deserialize(reader)
}
/**
* Non-inline variant for contexts where the target type is only known as a [KClass] at
* runtime (HTTP framework integrations — Retrofit `Type`, Ktor `TypeInfo`, Spring `Class<*>`).
*
* @throws IllegalArgumentException if no [GhostSerializer] is registered for [clazz].
*/
fun <T : Any> deserialize(bytes: ByteArray, clazz: KClass<T>): T {
val serializer = Ghost.getSerializer(clazz)
?: Ghost.throwError("${Ghost.NOT_FOUND} ${clazz.simpleName}. ${Ghost.MISSING_ANN}")
return serializer.deserialize(GhostProtoJsonFlatReader(bytes))
}
/**
* Encodes [value] using its registered [GhostSerializer]. proto3 JSON mapping (int64
* quoting, Base64 `bytes`, default-value omission) is already applied by the KSP-generated
* serializer for `@GhostProtoSerialization` classes, so this simply delegates to
* [Ghost.encodeToBytes] — kept here so callers have one consistent `GhostProtobuf.*`
* surface for both directions instead of mixing it with `Ghost.*`.
*/
inline fun <reified T : Any> encodeToBytes(value: T): ByteArray = Ghost.encodeToBytes(value)
/** Non-inline variant using a pre-resolved [serializer]; see [encodeToBytes]. */
fun <T : Any> encodeToBytes(serializer: GhostSerializer<T>, value: T): ByteArray =
Ghost.encodeToBytes(serializer, value)
/** String variant of [encodeToBytes]; see its documentation. */
inline fun <reified T : Any> encodeToString(value: T): String = Ghost.encodeToString(value)
inline fun <reified T : Any> deserialize(json: String): T {
return deserialize(json.encodeToByteArray())
}
inline fun <reified T : Any> deserialize(reader: GhostProtoJsonFlatReader): T {
val serializer = Ghost.resolveSerializer<T>()
return serializer.deserialize(reader)
}
inline fun <reified T : Any> deserialize(source: BufferedSource): T {
source.request(Long.MAX_VALUE)
val limit = source.buffer.size.toInt()
val bytes = acquireScratchBuffer(limit)
try {
var offset = 0
while (offset < limit) {
val count = source.read(bytes, offset, limit - offset)
if (count == -1) break
offset += count
}
// Zero-allocation slice range initialization on reader
val reader = GhostProtoJsonFlatReader(bytes)
reader.limit = offset
reader.position = 0
val serializer = Ghost.resolveSerializer<T>()
return serializer.deserialize(reader)
} finally {
releaseScratchBuffer(bytes)
}
}
}