Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kotlinx serialization support #179

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 48 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ fun Iterable<T>.toPersistentSet(): PersistentSet<T>
#### `+` and `-` operators

`plus` and `minus` operators on persistent collections exploit their immutability
and delegate the implementation to the collections themselves.
The operation is performed with persistence in mind: the returned immutable collection may share storage
and delegate the implementation to the collections themselves.
The operation is performed with persistence in mind: the returned immutable collection may share storage
with the original collection.

```kotlin
Expand All @@ -90,8 +90,8 @@ val newList = persistentListOf("a", "b") + "c"
```

> **Note:** you need to import these operators from `kotlinx.collections.immutable` package
in order for them to take the precedence over the ones from the
standard library.
> in order for them to take the precedence over the ones from the
> standard library.

```kotlin
import kotlinx.collections.immutable.*
Expand All @@ -112,6 +112,36 @@ With `mutate` it transforms to:
collection.mutate { some_actions_on(it) }
```

### Serialization

Serialization modules allows you to apply custom immutable collection serializers, for example:

```kotlin
@Serializable
private class MyCustomClass<K, V>(
@Serializable(with = ImmutableMapSerializer::class)
val immutableMap: ImmutableMap<K, V>
)
```

#### Collection Serializers

| Serializer | Conversion method
|-------------------------------|-------------------------
| `ImmutableListSerializer` | `toImmutableList()` |
| `PersistentListSerializer` | `toPersistentList()` |
| `ImmutableSetSerializer` | `toImmutableSet()` |
| `PersistentSetSerializer` | `toPersistentSet()` |
| `PersistentHashSetSerializer` | `toPersistentHashSet()` |

#### Map Serializers

| Serializer | Conversion method
|-------------------------------|-------------------------
| `ImmutableMapSerializer` | `toImmutableMap()` |
| `PersistentMapSerializer` | `toPersistentMap()` |
| `PersistentHashMapSerializer` | `toPersistentHashMap()` |

## Using in your projects

> Note that the library is experimental and the API is subject to change.
Expand All @@ -138,6 +168,7 @@ kotlin {
commonMain {
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8")
implementation("org.jetbrains.kotlinx:kotlinx-collections-immutable-serialization:0.3.8")
}
}
}
Expand All @@ -150,11 +181,19 @@ The Maven Central repository is available for dependency lookup by default.
Add dependencies (you can also add other modules that you need):

```xml
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-collections-immutable-jvm</artifactId>
<version>0.3.8</version>
</dependency>

<dependencies>
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-collections-immutable-jvm</artifactId>
<version>0.3.8</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-collections-immutable-serialization-jvm</artifactId>
<version>0.3.8</version>
</dependency>
</dependencies>
```

## Building from source
Expand Down
170 changes: 170 additions & 0 deletions serialization/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import kotlinx.team.infra.mavenPublicationsPom

plugins {
id("kotlin-multiplatform")
`maven-publish`
kotlin("plugin.serialization") version "1.9.21"
}

base {
archivesBaseName = "kotlinx-collections-immutable-serialization" // doesn't work
}

mavenPublicationsPom {
description.set("Kotlin Immutable Collections serializers")
}

kotlin {
applyDefaultHierarchyTemplate()
explicitApi()

// According to https://kotlinlang.org/docs/native-target-support.html
// Tier 1
linuxX64()
macosX64()
macosArm64()
iosSimulatorArm64()
iosX64()

// Tier 2
linuxArm64()
watchosSimulatorArm64()
watchosX64()
watchosArm32()
watchosArm64()
tvosSimulatorArm64()
tvosX64()
tvosArm64()
iosArm64()

// Tier 3
androidNativeArm32()
androidNativeArm64()
androidNativeX86()
androidNativeX64()
mingwX64()
watchosDeviceArm64()

jvm {
compilations.all {
kotlinOptions {
jvmTarget = "1.8"
}
}
}

js {
nodejs {
testTask {
useMocha {
timeout = "30000"
}
}
}
compilations.all {
kotlinOptions {
sourceMap = true
moduleKind = "umd"
metaInfo = true
}
}
}

wasmJs {
nodejs {
testTask {
useMocha {
timeout = "30000"
}
}
}
}

wasmWasi {
nodejs {
testTask {
useMocha {
timeout = "30000"
}
}
}
}

sourceSets.all {
kotlin.setSrcDirs(listOf("$name/src"))
resources.setSrcDirs(listOf("$name/resources"))
languageSettings.apply {
// progressiveMode = true
optIn("kotlin.RequiresOptIn")
}
}

sourceSets {
val commonMain by getting {
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
implementation(project(":kotlinx-collections-immutable"))
}
}
val commonTest by getting {
dependencies {
implementation(kotlin("test"))
}
}

val jvmMain by getting {
}
val jvmTest by getting {
dependencies {
implementation("com.google.guava:guava-testlib:18.0")
}
}

val jsMain by getting {
}
val jsTest by getting {
}

val wasmMain by creating {
dependsOn(commonMain)
}
val wasmTest by creating {
dependsOn(commonTest)
}

val wasmJsMain by getting {
dependsOn(wasmMain)
}
val wasmJsTest by getting {
dependsOn(wasmTest)
}

val wasmWasiMain by getting {
dependsOn(wasmMain)
}
val wasmWasiTest by getting {
dependsOn(wasmTest)
}

val nativeMain by getting {
}
val nativeTest by getting {
}
}
}

tasks {
named("jvmTest", Test::class) {
maxHeapSize = "1024m"
}
}

with(org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin.apply(rootProject)) {
nodeVersion = "21.0.0-v8-canary202309167e82ab1fa2"
nodeDownloadBaseUrl = "https://nodejs.org/download/v8-canary"
}

// Drop this when node js version become stable
tasks.withType<org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinNpmInstallTask>().configureEach {
args.add("--ignore-engines")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright 2016-2024 JetBrains s.r.o.
* Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file.
*/

package kotlinx.collections.immutable.serialization

import kotlinx.collections.immutable.ImmutableCollection
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.ImmutableSet
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.PersistentSet
import kotlinx.collections.immutable.toImmutableList
import kotlinx.collections.immutable.toImmutableSet
import kotlinx.collections.immutable.toPersistentHashSet
import kotlinx.collections.immutable.toPersistentList
import kotlinx.collections.immutable.toPersistentSet
import kotlinx.serialization.KSerializer
import kotlinx.serialization.builtins.ListSerializer
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder

internal class DefaultImmutableCollectionSerializer<T, C : ImmutableCollection<T>>(
serializer: KSerializer<T>,
private val transform: (Collection<T>) -> C
) : KSerializer<C> {
private val listSerializer = ListSerializer(serializer)

override val descriptor: SerialDescriptor = serializer.descriptor

override fun serialize(encoder: Encoder, value: C) {
return listSerializer.serialize(encoder, value.toList())
}

override fun deserialize(decoder: Decoder): C {
return listSerializer.deserialize(decoder).let(transform)
}
}

public class ImmutableListSerializer<T>(
serializer: KSerializer<T>
) : KSerializer<ImmutableList<T>> by DefaultImmutableCollectionSerializer(
serializer = serializer,
transform = { decodedList -> decodedList.toImmutableList() }
)

public class PersistentListSerializer<T>(
serializer: KSerializer<T>
) : KSerializer<PersistentList<T>> by DefaultImmutableCollectionSerializer(
serializer = serializer,
transform = { decodedList -> decodedList.toPersistentList() }
)

public class ImmutableSetSerializer<T>(
serializer: KSerializer<T>
) : KSerializer<ImmutableSet<T>> by DefaultImmutableCollectionSerializer(
serializer = serializer,
transform = { decodedList -> decodedList.toImmutableSet() }
)

public class PersistentSetSerializer<T>(
serializer: KSerializer<T>
) : KSerializer<PersistentSet<T>> by DefaultImmutableCollectionSerializer(
serializer = serializer,
transform = { decodedList -> decodedList.toPersistentSet() }
)

public class PersistentHashSetSerializer<T>(
serializer: KSerializer<T>
) : KSerializer<PersistentSet<T>> by DefaultImmutableCollectionSerializer(
serializer = serializer,
transform = { decodedList -> decodedList.toPersistentHashSet() }
)
Loading