feature/root #69
@ -1,15 +1,9 @@
|
||||
package ru.mipt.npm.root
|
||||
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonDecoder
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.modules.SerializersModule
|
||||
import kotlinx.serialization.modules.polymorphic
|
||||
import kotlinx.serialization.modules.subclass
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import kotlinx.serialization.json.decodeFromJsonElement
|
||||
|
||||
@Serializable
|
||||
@SerialName("TGeoManager")
|
||||
@ -26,113 +20,10 @@ public class TGeoManager : TNamed() {
|
||||
/**
|
||||
* Load Json encoded TGeoManager
|
||||
*/
|
||||
public fun decodeFromJson(jsonObject: JsonObject): TGeoManager = TODO()
|
||||
public fun decodeFromJson(jsonElement: JsonElement): TGeoManager =
|
||||
rootJson().decodeFromJsonElement(jsonElement)
|
||||
|
||||
public fun decodeFromString(string: String): TGeoManager =
|
||||
Root().decodeFromString(serializer(), string)
|
||||
rootJson().decodeFromString(serializer(), string)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
private class RootJsonSerializer<T>(private val tSerializer: KSerializer<T>) : KSerializer<T> {
|
||||
|
||||
private val refCache: HashMap<UInt, TObject> = HashMap()
|
||||
|
||||
|
||||
override val descriptor: SerialDescriptor get() = tSerializer.descriptor
|
||||
|
||||
|
||||
override fun deserialize(decoder: Decoder): T {
|
||||
val input = decoder as JsonDecoder
|
||||
val element = input.decodeJsonElement()
|
||||
return input.json.decodeFromJsonElement(tSerializer, transformDeserialize(element))
|
||||
}
|
||||
|
||||
override fun serialize(encoder: Encoder, value: T) {
|
||||
tSerializer.serialize(encoder, value)
|
||||
}
|
||||
|
||||
override fun <T> decodeFromString(deserializer: DeserializationStrategy<T>, string: String): T {
|
||||
val match = refRegex.matchEntire(string)
|
||||
return if (match != null) {
|
||||
//Do unref
|
||||
val ref = match.value.toUIntOrNull() ?: error("Ref value is not a number")
|
||||
val refValue = refCache[ref] ?: error("Reference $ref unresolved")
|
||||
refValue as T //TODO research means to make it safe
|
||||
} else {
|
||||
val res = rootJson.decodeFromString(deserializer, string)
|
||||
val uid = (res as? TObject)?.fUniqueID
|
||||
if (uid != null && refCache[uid] == null) {
|
||||
refCache[uid] = res
|
||||
}
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun <T> encodeToString(serializer: SerializationStrategy<T>, value: T): String =
|
||||
rootJson.encodeToString(serializer, value)
|
||||
|
||||
companion object {
|
||||
val refRegex = """\{\s*"${"\\$"}ref"\s*:\s*(\d*)}""".toRegex()
|
||||
|
||||
val rootSerializersModule = SerializersModule {
|
||||
polymorphic(TGeoShape::class) {
|
||||
subclass(TGeoBBox.serializer())
|
||||
subclass(TGeoCompositeShape.serializer())
|
||||
subclass(TGeoXtru.serializer())
|
||||
subclass(TGeoTube.serializer())
|
||||
subclass(TGeoTubeSeg.serializer())
|
||||
subclass(TGeoShapeAssembly.serializer())
|
||||
}
|
||||
|
||||
polymorphic(TGeoMatrix::class) {
|
||||
subclass(TGeoIdentity.serializer())
|
||||
subclass(TGeoHMatrix.serializer())
|
||||
subclass(TGeoTranslation.serializer())
|
||||
subclass(TGeoRotation.serializer())
|
||||
subclass(TGeoCombiTrans.serializer())
|
||||
}
|
||||
|
||||
polymorphic(TObject::class) {
|
||||
subclass(TGeoBBox.serializer())
|
||||
subclass(TGeoCompositeShape.serializer())
|
||||
subclass(TGeoXtru.serializer())
|
||||
subclass(TGeoTube.serializer())
|
||||
subclass(TGeoTubeSeg.serializer())
|
||||
subclass(TGeoShapeAssembly.serializer())
|
||||
|
||||
subclass(TGeoIdentity.serializer())
|
||||
subclass(TGeoHMatrix.serializer())
|
||||
subclass(TGeoTranslation.serializer())
|
||||
subclass(TGeoRotation.serializer())
|
||||
subclass(TGeoCombiTrans.serializer())
|
||||
|
||||
subclass(TGeoMaterial.serializer())
|
||||
subclass(TGeoMixture.serializer())
|
||||
|
||||
subclass(TGeoMedium.serializer())
|
||||
|
||||
subclass(TGeoNode.serializer())
|
||||
subclass(TGeoNodeMatrix.serializer())
|
||||
subclass(TGeoVolume.serializer())
|
||||
subclass(TGeoVolumeAssembly.serializer())
|
||||
}
|
||||
polymorphic(TGeoNode::class, TGeoNode.serializer()) {
|
||||
subclass(TGeoNodeMatrix.serializer())
|
||||
}
|
||||
polymorphic(TGeoVolume::class, TGeoVolume.serializer()) {
|
||||
subclass(TGeoVolumeAssembly.serializer())
|
||||
}
|
||||
}
|
||||
|
||||
val rootJson: Json = Json {
|
||||
encodeDefaults = true
|
||||
ignoreUnknownKeys = true
|
||||
classDiscriminator = "_typename"
|
||||
serializersModule = rootSerializersModule
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,107 @@
|
||||
package ru.mipt.npm.root
|
||||
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import kotlinx.serialization.json.*
|
||||
import kotlinx.serialization.modules.PolymorphicModuleBuilder
|
||||
import kotlinx.serialization.modules.SerializersModule
|
||||
import kotlinx.serialization.modules.polymorphic
|
||||
import kotlinx.serialization.modules.subclass
|
||||
|
||||
|
||||
private typealias RefCache = MutableList<TObject>
|
||||
|
||||
private class RootJsonSerializer<T : TObject>(
|
||||
private val refCache: RefCache,
|
||||
private val tSerializer: KSerializer<T>
|
||||
) : KSerializer<T> {
|
||||
|
||||
override val descriptor: SerialDescriptor get() = tSerializer.descriptor
|
||||
|
||||
override fun deserialize(decoder: Decoder): T {
|
||||
val input = decoder as JsonDecoder
|
||||
val element = input.decodeJsonElement()
|
||||
val refId = (element as? JsonObject)?.get("\$ref")?.jsonPrimitive?.int
|
||||
return if (refId != null) {
|
||||
//Do unref
|
||||
val refValue = refCache[refId]
|
||||
refValue as T //TODO research means to make it safe
|
||||
} else {
|
||||
val res = input.json.decodeFromJsonElement(tSerializer, element)
|
||||
//val uid = res.fUniqueID
|
||||
refCache.add(res)
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
override fun serialize(encoder: Encoder, value: T) {
|
||||
tSerializer.serialize(encoder, value)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun <T : TObject> KSerializer<T>.unref(refCache: RefCache): RootJsonSerializer<T> =
|
||||
RootJsonSerializer(refCache, this)
|
||||
|
||||
|
||||
private fun PolymorphicModuleBuilder<TGeoShape>.shapes(refCache: RefCache) {
|
||||
subclass(TGeoBBox.serializer().unref(refCache))
|
||||
subclass(TGeoCompositeShape.serializer().unref(refCache))
|
||||
subclass(TGeoXtru.serializer().unref(refCache))
|
||||
subclass(TGeoTube.serializer().unref(refCache))
|
||||
subclass(TGeoTubeSeg.serializer().unref(refCache))
|
||||
subclass(TGeoShapeAssembly.serializer().unref(refCache))
|
||||
}
|
||||
|
||||
private fun PolymorphicModuleBuilder<TGeoMatrix>.matrices(refCache: RefCache) {
|
||||
subclass(TGeoIdentity.serializer().unref(refCache))
|
||||
subclass(TGeoHMatrix.serializer().unref(refCache))
|
||||
subclass(TGeoTranslation.serializer().unref(refCache))
|
||||
subclass(TGeoRotation.serializer().unref(refCache))
|
||||
subclass(TGeoCombiTrans.serializer().unref(refCache))
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of Json with unfolding Root references. This instance could not be reused because of the cache.
|
||||
*/
|
||||
internal fun rootJson(): Json {
|
||||
val refCache = ArrayList<TObject>(4096)
|
||||
return Json {
|
||||
encodeDefaults = true
|
||||
ignoreUnknownKeys = true
|
||||
classDiscriminator = "_typename"
|
||||
serializersModule = SerializersModule {
|
||||
polymorphic(TGeoShape::class) {
|
||||
default { TGeoBBox.serializer().unref(refCache) }
|
||||
shapes(refCache)
|
||||
}
|
||||
|
||||
polymorphic(TGeoMatrix::class) {
|
||||
matrices(refCache)
|
||||
}
|
||||
|
||||
polymorphic(TObject::class) {
|
||||
shapes(refCache)
|
||||
matrices(refCache)
|
||||
|
||||
subclass(TGeoMaterial.serializer().unref(refCache))
|
||||
subclass(TGeoMixture.serializer().unref(refCache))
|
||||
|
||||
subclass(TGeoMedium.serializer().unref(refCache))
|
||||
|
||||
subclass(TGeoNode.serializer().unref(refCache))
|
||||
subclass(TGeoNodeMatrix.serializer().unref(refCache))
|
||||
subclass(TGeoVolume.serializer().unref(refCache))
|
||||
subclass(TGeoVolumeAssembly.serializer().unref(refCache))
|
||||
}
|
||||
polymorphic(TGeoNode::class, TGeoNode.serializer().unref(refCache)) {
|
||||
subclass(TGeoNodeMatrix.serializer().unref(refCache))
|
||||
}
|
||||
polymorphic(TGeoVolume::class, TGeoVolume.serializer().unref(refCache)) {
|
||||
subclass(TGeoVolumeAssembly.serializer().unref(refCache))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user