From c7d4a7e1f1e50b580e5ea00f0138506c2e8d6dbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Galczak?= Date: Fri, 22 Dec 2023 13:41:54 +0100 Subject: [PATCH] Add support for serializing kotlin.time.Duration in Parcelize plugin. This commit adds support for the Parcelize plugin to generate default serialization implementation for the kotlin.time.Duration. As Parcelize already supports serializing some of the kotlin library types it makes sense to support more common ones for the user convenience. https://issuetracker.google.com/issues/264614661 --- .../kotlin/parcelize/AndroidSymbols.kt | 7 ++++ .../parcelize/IrParcelSerializerFactory.kt | 10 +++++ .../parcelize/BuiltinParcelableTypes.kt | 3 +- .../testData/box/duration.kt | 42 +++++++++++++++++++ ...ParcelizeFirLightTreeBoxTestGenerated.java | 6 +++ .../runners/ParcelizeIrBoxTestGenerated.java | 6 +++ 6 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 plugins/parcelize/parcelize-compiler/testData/box/duration.kt diff --git a/plugins/parcelize/parcelize-compiler/parcelize.backend/src/org/jetbrains/kotlin/parcelize/AndroidSymbols.kt b/plugins/parcelize/parcelize-compiler/parcelize.backend/src/org/jetbrains/kotlin/parcelize/AndroidSymbols.kt index 4c850b9c4f0..9de260ba49d 100644 --- a/plugins/parcelize/parcelize-compiler/parcelize.backend/src/org/jetbrains/kotlin/parcelize/AndroidSymbols.kt +++ b/plugins/parcelize/parcelize-compiler/parcelize.backend/src/org/jetbrains/kotlin/parcelize/AndroidSymbols.kt @@ -47,6 +47,7 @@ class AndroidSymbols( private val kotlin: IrPackageFragment = createPackage("kotlin") private val kotlinJvm: IrPackageFragment = createPackage("kotlin.jvm") private val kotlinJvmInternalPackage: IrPackageFragment = createPackage("kotlin.jvm.internal") + private val kotlinTime: IrPackageFragment = createPackage("kotlin.time") private val androidOs: IrPackageFragment = createPackage("android.os") private val androidUtil: IrPackageFragment = createPackage("android.util") @@ -185,6 +186,12 @@ class AndroidSymbols( } }.symbol + val kotlinTimeDuration: IrClassSymbol = createClass( + kotlinTime, "Duration", ClassKind.CLASS, Modality.FINAL, true + ).apply { + owner.valueClassRepresentation = InlineClassRepresentation(Name.identifier("rawValue"), irBuiltIns.longType as IrSimpleType) + } + val kotlinKClassJava: IrPropertySymbol = irFactory.buildProperty { name = Name.identifier("java") }.apply { diff --git a/plugins/parcelize/parcelize-compiler/parcelize.backend/src/org/jetbrains/kotlin/parcelize/IrParcelSerializerFactory.kt b/plugins/parcelize/parcelize-compiler/parcelize.backend/src/org/jetbrains/kotlin/parcelize/IrParcelSerializerFactory.kt index 728b2f35afd..8867dec2941 100644 --- a/plugins/parcelize/parcelize-compiler/parcelize.backend/src/org/jetbrains/kotlin/parcelize/IrParcelSerializerFactory.kt +++ b/plugins/parcelize/parcelize-compiler/parcelize.backend/src/org/jetbrains/kotlin/parcelize/IrParcelSerializerFactory.kt @@ -153,6 +153,9 @@ class IrParcelSerializerFactory(private val symbols: AndroidSymbols) { return uintArraySerializer "kotlin.ULongArray" -> return ulongArraySerializer + // Library types + "kotlin.time.Duration" -> + return wrapNullableSerializerIfNeeded(irType, durationSerializer) } // Generic container types @@ -429,4 +432,11 @@ class IrParcelSerializerFactory(private val symbols: AndroidSymbols) { private val sizeFSerializer = IrSimpleParcelSerializer(symbols.parcelReadSizeF, symbols.parcelWriteSizeF) private val sparseBooleanArraySerializer = IrSimpleParcelSerializer(symbols.parcelReadSparseBooleanArray, symbols.parcelWriteSparseBooleanArray) + + // library types serializers + private val durationSerializer = IrUnsafeCoerceWrappedSerializer( + longSerializer, + symbols.kotlinTimeDuration.defaultType, + irBuiltIns.longType + ) } diff --git a/plugins/parcelize/parcelize-compiler/parcelize.common/src/org/jetbrains/kotlin/parcelize/BuiltinParcelableTypes.kt b/plugins/parcelize/parcelize-compiler/parcelize.common/src/org/jetbrains/kotlin/parcelize/BuiltinParcelableTypes.kt index d4ff18b1985..025939d17de 100644 --- a/plugins/parcelize/parcelize-compiler/parcelize.common/src/org/jetbrains/kotlin/parcelize/BuiltinParcelableTypes.kt +++ b/plugins/parcelize/parcelize-compiler/parcelize.common/src/org/jetbrains/kotlin/parcelize/BuiltinParcelableTypes.kt @@ -86,6 +86,7 @@ object BuiltinParcelableTypes { "kotlin.ULongArray", "kotlin.UShort", "kotlin.UShortArray", + "kotlin.time.Duration", ) + PARCELABLE_SUPERTYPE_FQNAMES val PARCELABLE_CONTAINER_FQNAMES = setOf( @@ -120,4 +121,4 @@ object BuiltinParcelableTypes { "kotlin.collections.Set", *IMMUTABLE_COLLECTIONS_FQNAMES.toTypedArray(), ) -} +} \ No newline at end of file diff --git a/plugins/parcelize/parcelize-compiler/testData/box/duration.kt b/plugins/parcelize/parcelize-compiler/testData/box/duration.kt new file mode 100644 index 00000000000..7f4a7d2c568 --- /dev/null +++ b/plugins/parcelize/parcelize-compiler/testData/box/duration.kt @@ -0,0 +1,42 @@ +// WITH_STDLIB + +@file:JvmName("TestKt") +package test + +import kotlinx.parcelize.* +import android.os.Parcelable +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds +import kotlin.time.Duration.Companion.nanoseconds + +@Parcelize +data class Test( + val basic: Duration, + val negative: Duration, + val nullable: Duration?, + val nullableWithValue: Duration?, + val noNanoseconds: Duration, + val noSeconds: Duration, + val infinite: Duration, + val negativeInfinite: Duration, +) : Parcelable + + +fun box() = parcelTest { parcel -> + val test = Test( + basic = 10.seconds + 2.nanoseconds, + negative = -10.seconds - 2.nanoseconds, + nullable = null, + nullableWithValue = 10.seconds + 2.nanoseconds, + noNanoseconds = 10.seconds, + noSeconds = 2.nanoseconds, + infinite = Duration.INFINITE, + negativeInfinite = -Duration.INFINITE, + ) + test.writeToParcel(parcel, 0) + val bytes = parcel.marshall() + parcel.unmarshall(bytes, 0, bytes.size) + parcel.setDataPosition(0) + val got = parcelableCreator().createFromParcel(parcel) + assert(test == got) +} diff --git a/plugins/parcelize/parcelize-compiler/tests-gen/org/jetbrains/kotlin/parcelize/test/runners/ParcelizeFirLightTreeBoxTestGenerated.java b/plugins/parcelize/parcelize-compiler/tests-gen/org/jetbrains/kotlin/parcelize/test/runners/ParcelizeFirLightTreeBoxTestGenerated.java index 9d8ccd9f60a..41295a19031 100644 --- a/plugins/parcelize/parcelize-compiler/tests-gen/org/jetbrains/kotlin/parcelize/test/runners/ParcelizeFirLightTreeBoxTestGenerated.java +++ b/plugins/parcelize/parcelize-compiler/tests-gen/org/jetbrains/kotlin/parcelize/test/runners/ParcelizeFirLightTreeBoxTestGenerated.java @@ -127,6 +127,12 @@ public class ParcelizeFirLightTreeBoxTestGenerated extends AbstractParcelizeFirL runTest("plugins/parcelize/parcelize-compiler/testData/box/customSimple.kt"); } + @Test + @TestMetadata("duration.kt") + public void testDuration() throws Exception { + runTest("plugins/parcelize/parcelize-compiler/testData/box/duration.kt"); + } + @Test @TestMetadata("enumObject.kt") public void testEnumObject() throws Exception { diff --git a/plugins/parcelize/parcelize-compiler/tests-gen/org/jetbrains/kotlin/parcelize/test/runners/ParcelizeIrBoxTestGenerated.java b/plugins/parcelize/parcelize-compiler/tests-gen/org/jetbrains/kotlin/parcelize/test/runners/ParcelizeIrBoxTestGenerated.java index 84875b258d6..311cd49774c 100644 --- a/plugins/parcelize/parcelize-compiler/tests-gen/org/jetbrains/kotlin/parcelize/test/runners/ParcelizeIrBoxTestGenerated.java +++ b/plugins/parcelize/parcelize-compiler/tests-gen/org/jetbrains/kotlin/parcelize/test/runners/ParcelizeIrBoxTestGenerated.java @@ -127,6 +127,12 @@ public class ParcelizeIrBoxTestGenerated extends AbstractParcelizeIrBoxTest { runTest("plugins/parcelize/parcelize-compiler/testData/box/customSimple.kt"); } + @Test + @TestMetadata("duration.kt") + public void testDuration() throws Exception { + runTest("plugins/parcelize/parcelize-compiler/testData/box/duration.kt"); + } + @Test @TestMetadata("enumObject.kt") public void testEnumObject() throws Exception {