From 5d2c853cbec6138bb53fc5580ada6eb76ca50e4b Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Fri, 20 Aug 2021 20:25:19 +0300 Subject: [PATCH] WIP ROOT json serialization --- build.gradle.kts | 7 +- .../kotlin/ru/mipt/npm/root/RootModel.kt | 25 ------ .../kotlin/ru/mipt/npm/root/TGeoHMatrix.kt | 7 ++ .../kotlin/ru/mipt/npm/root/TGeoManager.kt | 88 +++++++++++++++++-- .../kotlin/ru/mipt/npm/root/TGeoMaterial.kt | 3 + .../kotlin/ru/mipt/npm/root/TGeoMedium.kt | 2 + .../kotlin/ru/mipt/npm/root/TGeoNode.kt | 8 +- .../kotlin/ru/mipt/npm/root/TGeoShape.kt | 34 ++++++- .../kotlin/ru/mipt/npm/root/TGeoVolume.kt | 3 + .../kotlin/ru/mipt/npm/root/TObject.kt | 2 + .../kotlin/ru/mipt/npm/root/loadBM@N.kt | 7 ++ 11 files changed, 144 insertions(+), 42 deletions(-) delete mode 100644 cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/RootModel.kt create mode 100644 cern-root-loader/src/jvmTest/kotlin/ru/mipt/npm/root/loadBM@N.kt diff --git a/build.gradle.kts b/build.gradle.kts index 505c349c..cd6ece5d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -37,8 +37,7 @@ apiValidation { } -afterEvaluate { - extensions.configure { - versions.webpackDevServer.version = "4.0.0" - } +//workaround for https://youtrack.jetbrains.com/issue/KT-48273 +rootProject.plugins.withType(org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin::class.java) { + rootProject.the().versions.webpackDevServer.version = "4.0.0" } \ No newline at end of file diff --git a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/RootModel.kt b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/RootModel.kt deleted file mode 100644 index 8f53d71f..00000000 --- a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/RootModel.kt +++ /dev/null @@ -1,25 +0,0 @@ -package ru.mipt.npm.root - -import kotlin.properties.PropertyDelegateProvider -import kotlin.reflect.KType -import kotlin.reflect.typeOf - -public interface RootValueProvider { - /** - * Provide a member cast or reinterpreted to given type. - * Returns null if member with given name/type could not be resolved. - */ - public fun provideOrNull(name: String, type: KType): T? -} - -public interface RootModel { - public val provider: RootValueProvider -} - -public inline fun RootValueProvider.provide(name: String): T = - provideOrNull(name, typeOf()) ?: error("A member with type ${T::class} and name $name could not be resolved") - -public inline fun RootModel.member(name: String? = null): PropertyDelegateProvider> = - PropertyDelegateProvider { _, property -> - lazy { provider.provide(name ?: property.name) } - } diff --git a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoHMatrix.kt b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoHMatrix.kt index f70e9a24..3e1362f8 100644 --- a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoHMatrix.kt +++ b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoHMatrix.kt @@ -1,15 +1,19 @@ package ru.mipt.npm.root +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable +@SerialName("TGeoMatrix") public sealed class TGeoMatrix : TNamed() @Serializable +@SerialName("TGeoIdentity") public class TGeoIdentity : TGeoMatrix() @Serializable +@SerialName("TGeoHMatrix") public class TGeoHMatrix( public val fTranslation: DoubleArray, public val fRotationMatrix: DoubleArray, @@ -17,16 +21,19 @@ public class TGeoHMatrix( ) : TGeoMatrix() @Serializable +@SerialName("TGeoTranslation") public class TGeoTranslation( public val fTranslation: DoubleArray ) : TGeoMatrix() @Serializable +@SerialName("TGeoRotation") public class TGeoRotation( public val fRotationMatrix: DoubleArray ): TGeoMatrix() @Serializable +@SerialName("TGeoCombiTrans") public class TGeoCombiTrans( public val fTranslation: DoubleArray, public val fRotation: TGeoRotation? = null, diff --git a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoManager.kt b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoManager.kt index 557783ae..acf4d712 100644 --- a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoManager.kt +++ b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoManager.kt @@ -1,11 +1,18 @@ 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 @Serializable +@SerialName("TGeoManager") public class TGeoManager : TNamed() { public val fMatrices: TObjArray = TObjArray.empty @@ -20,19 +27,31 @@ public class TGeoManager : TNamed() { * Load Json encoded TGeoManager */ public fun decodeFromJson(jsonObject: JsonObject): TGeoManager = TODO() - + public fun decodeFromString(string: String): TGeoManager = - RootJsonSerialFormat().decodeFromString(serializer(), string) + Root().decodeFromString(serializer(), string) } } @OptIn(ExperimentalSerializationApi::class) -private class RootJsonSerialFormat : StringFormat { - - override val serializersModule: SerializersModule get() = json.serializersModule +private class RootJsonSerializer(private val tSerializer: KSerializer) : KSerializer { private val refCache: HashMap = 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 decodeFromString(deserializer: DeserializationStrategy, string: String): T { val match = refRegex.matchEntire(string) return if (match != null) { @@ -41,7 +60,7 @@ private class RootJsonSerialFormat : StringFormat { val refValue = refCache[ref] ?: error("Reference $ref unresolved") refValue as T //TODO research means to make it safe } else { - val res = json.decodeFromString(deserializer, string) + val res = rootJson.decodeFromString(deserializer, string) val uid = (res as? TObject)?.fUniqueID if (uid != null && refCache[uid] == null) { refCache[uid] = res @@ -50,17 +69,70 @@ private class RootJsonSerialFormat : StringFormat { } } + override fun encodeToString(serializer: SerializationStrategy, value: T): String = - json.encodeToString(serializer, value) + rootJson.encodeToString(serializer, value) companion object { val refRegex = """\{\s*"${"\\$"}ref"\s*:\s*(\d*)}""".toRegex() - val json: Json = Json { + 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 } + } } diff --git a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoMaterial.kt b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoMaterial.kt index 9094d721..f4883e0e 100644 --- a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoMaterial.kt +++ b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoMaterial.kt @@ -1,9 +1,12 @@ package ru.mipt.npm.root +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable +@SerialName("TGeoMaterial") public open class TGeoMaterial: TNamed() @Serializable +@SerialName("TGeoMixture") public class TGeoMixture: TGeoMaterial() \ No newline at end of file diff --git a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoMedium.kt b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoMedium.kt index 196c209c..3e598753 100644 --- a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoMedium.kt +++ b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoMedium.kt @@ -1,8 +1,10 @@ package ru.mipt.npm.root +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable +@SerialName("TGeoMedium") public class TGeoMedium( public val fId : Int, public val fMaterial: TGeoMaterial, diff --git a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoNode.kt b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoNode.kt index 2793773f..5805f3ea 100644 --- a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoNode.kt +++ b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoNode.kt @@ -1,9 +1,11 @@ package ru.mipt.npm.root +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable -public class TGeoNode : TNamed() { +@SerialName("TGeoNode") +public open class TGeoNode : TNamed() { //val fGeoAtt: UInt public val fVolume: TGeoVolume? = null public val fMother: TGeoVolume? = null @@ -12,6 +14,8 @@ public class TGeoNode : TNamed() { public val fOverlaps: IntArray = intArrayOf() } -public class TGeoNodeMatrix : TGeoMatrix() { +@Serializable +@SerialName("TGeoNodeMatrix") +public class TGeoNodeMatrix : TGeoNode() { public val fMatrix: TGeoMatrix? = null } \ No newline at end of file diff --git a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoShape.kt b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoShape.kt index 344f5e6f..f26261da 100644 --- a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoShape.kt +++ b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoShape.kt @@ -1,14 +1,17 @@ package ru.mipt.npm.root +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable -public abstract class TGeoShape : TNamed() { +@SerialName("TGeoShape") +public sealed class TGeoShape : TNamed() { public val fShapeBits: UInt = 0u public val fShapeId: Int = 0 } @Serializable +@SerialName("TGeoBBox") public open class TGeoBBox : TGeoShape() { public val fDX: Double = 0.0 public val fDY: Double = 0.0 @@ -17,6 +20,7 @@ public open class TGeoBBox : TGeoShape() { } @Serializable +@SerialName("TGeoBoolNode") public sealed class TGeoBoolNode : TObject() { public abstract val fLeft: TGeoShape public abstract val fLeftMat: TGeoMatrix @@ -25,6 +29,7 @@ public sealed class TGeoBoolNode : TObject() { } @Serializable +@SerialName("TGeoUnion") public class TGeoUnion( override val fLeft: TGeoShape, override val fLeftMat: TGeoMatrix, @@ -33,6 +38,7 @@ public class TGeoUnion( ) : TGeoBoolNode() @Serializable +@SerialName("TGeoSubtraction") public class TGeoSubtraction( override val fLeft: TGeoShape, override val fLeftMat: TGeoMatrix, @@ -41,6 +47,7 @@ public class TGeoSubtraction( ) : TGeoBoolNode() @Serializable +@SerialName("TGeoIntersection") public class TGeoIntersection( override val fLeft: TGeoShape, override val fLeftMat: TGeoMatrix, @@ -50,9 +57,11 @@ public class TGeoIntersection( @Serializable +@SerialName("TGeoCompositeShape") public class TGeoCompositeShape(public val fNode: TGeoBoolNode) : TGeoBBox() @Serializable +@SerialName("TGeoXtru") public class TGeoXtru( public val fNvert: Int, public val fNz: Int, @@ -67,14 +76,33 @@ public class TGeoXtru( @Serializable -public class TGeoTube( +@SerialName("TGeoTube") +public open class TGeoTube( public val fRmin: Double, public val fRmax: Double, public val fDz: Double, ) : TGeoBBox() @Serializable +@SerialName("TGeoTubeSeg") +public class TGeoTubeSeg( + public val fRmin: Double, + public val fRmax: Double, + public val fDz: Double, + public val fPhi1: Double, + public val fPhi2: Double, + public val fS1: Double, + public val fC1: Double, + public val fS2: Double, + public val fC2: Double, + public val fSm: Double, + public val fCm: Double, + public val fCdfi: Double, +) : TGeoBBox() + +@Serializable +@SerialName("TGeoShapeAssembly") public class TGeoShapeAssembly( public val fVolume: TGeoVolumeAssembly, public val fBBoxOK: Boolean = true -): TGeoBBox() \ No newline at end of file +) : TGeoBBox() \ No newline at end of file diff --git a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoVolume.kt b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoVolume.kt index 1bd12cbf..dc986729 100644 --- a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoVolume.kt +++ b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TGeoVolume.kt @@ -1,8 +1,10 @@ package ru.mipt.npm.root +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable +@SerialName("TGeoVolume") public open class TGeoVolume : TNamed(){ // "fGeoAtt" : 3084, // "fLineColor" : 3, @@ -19,4 +21,5 @@ public open class TGeoVolume : TNamed(){ } @Serializable +@SerialName("TGeoVolumeAssembly") public class TGeoVolumeAssembly : TGeoVolume() \ No newline at end of file diff --git a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TObject.kt b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TObject.kt index fb17d8ac..bf528e6f 100644 --- a/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TObject.kt +++ b/cern-root-loader/src/commonMain/kotlin/ru/mipt/npm/root/TObject.kt @@ -1,5 +1,6 @@ package ru.mipt.npm.root +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable @@ -15,6 +16,7 @@ public abstract class TNamed : TObject() { } @Serializable +@SerialName("TObjArray") public class TObjArray(public val arr: List){ public companion object{ public val empty = TObjArray(emptyList()) diff --git a/cern-root-loader/src/jvmTest/kotlin/ru/mipt/npm/root/loadBM@N.kt b/cern-root-loader/src/jvmTest/kotlin/ru/mipt/npm/root/loadBM@N.kt new file mode 100644 index 00000000..5d3a03af --- /dev/null +++ b/cern-root-loader/src/jvmTest/kotlin/ru/mipt/npm/root/loadBM@N.kt @@ -0,0 +1,7 @@ +package ru.mipt.npm.root + +fun main() { + val string = TGeoManager::class.java.getResourceAsStream("/BM@N.root.json")!! + .readAllBytes().decodeToString() + val geo = TGeoManager.decodeFromString(string) +} \ No newline at end of file