Coverage Summary for Class: GhostContentConverter (com.ghost.serialization.ktor)
| Class |
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
| GhostContentConverter |
80%
(4/5)
|
80%
(16/20)
|
97.2%
(35/36)
|
94.9%
(166/175)
|
| GhostContentConverter$Companion |
|
| GhostContentConverter$deserialize$1 |
|
| Total |
80%
(4/5)
|
80%
(16/20)
|
97.2%
(35/36)
|
94.9%
(166/175)
|
package com.ghost.serialization.ktor
import com.ghost.serialization.Ghost
import com.ghost.serialization.InternalGhostApi
import com.ghost.serialization.acquireScratchBuffer
import com.ghost.serialization.ghostInternalUseFlatReader
import com.ghost.serialization.releaseScratchBuffer
import com.ghost.serialization.parser.GhostJsonReader
import com.ghost.serialization.parser.GhostJsonFlatReader
import io.ktor.http.ContentType
import io.ktor.http.content.ByteArrayContent
import io.ktor.http.content.OutgoingContent
import io.ktor.serialization.ContentConverter
import io.ktor.util.reflect.TypeInfo
import io.ktor.utils.io.ByteReadChannel
import io.ktor.utils.io.charsets.Charset
import kotlin.reflect.KClass
@OptIn(InternalGhostApi::class)
class GhostContentConverter(
private val configurer: ((GhostJsonFlatReader) -> Unit)? = null
) : ContentConverter {
@Suppress("UNCHECKED_CAST")
override suspend fun serializeNullable(
contentType: ContentType,
charset: Charset,
typeInfo: TypeInfo,
value: Any?
): OutgoingContent? {
if (value == null) return null
val clazz = typeInfo.type
val serializer = typeInfo.kotlinType?.let { Ghost.getSerializer(it) }
?: Ghost.getSerializer(clazz as KClass<Any>)
?: return null
val bytes = Ghost.encodeToBytes(serializer, value)
return ByteArrayContent(bytes, contentType)
}
@Suppress("UNCHECKED_CAST")
override suspend fun deserialize(
charset: Charset,
typeInfo: TypeInfo,
content: ByteReadChannel
): Any? {
val serializer = typeInfo.kotlinType?.let { Ghost.getSerializer(it) }
?: Ghost.getSerializer(typeInfo.type as KClass<Any>)
?: return null
var scratch =
acquireScratchBuffer(BUFFER_SIZE)
try {
var offset = 0
while (true) {
if (offset == scratch.size) {
val grown =
acquireScratchBuffer(scratch.size * 2)
scratch.copyInto(
grown,
0,
0,
offset
)
releaseScratchBuffer(scratch)
scratch = grown
}
val read = content.readAvailable(
scratch,
offset,
scratch.size - offset
)
if (read == -1) break
offset += read
}
return ghostInternalUseFlatReader(scratch, offset) { reader ->
configurer?.invoke(reader)
serializer.deserialize(reader)
}
} finally {
releaseScratchBuffer(scratch)
}
}
companion object {
private const val BUFFER_SIZE = 524288
}
}