feature/root #69
@ -1,15 +1,9 @@
|
|||||||
package ru.mipt.npm.root
|
package ru.mipt.npm.root
|
||||||
|
|
||||||
import kotlinx.serialization.*
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.descriptors.SerialDescriptor
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.encoding.Decoder
|
import kotlinx.serialization.json.JsonElement
|
||||||
import kotlinx.serialization.encoding.Encoder
|
import kotlinx.serialization.json.decodeFromJsonElement
|
||||||
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
|
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@SerialName("TGeoManager")
|
@SerialName("TGeoManager")
|
||||||
@ -26,113 +20,10 @@ public class TGeoManager : TNamed() {
|
|||||||
/**
|
/**
|
||||||
* Load Json encoded TGeoManager
|
* 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 =
|
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