diff --git a/content/docs/migration_1.0/Kotlin.md b/content/docs/migration_1.0/Kotlin.md index 43e1c2ee..145f3664 100644 --- a/content/docs/migration_1.0/Kotlin.md +++ b/content/docs/migration_1.0/Kotlin.md @@ -70,12 +70,6 @@ In 1.0.0. the previous example would instead now become: val encoding = Encoding.TEXT_JSON ``` -Custom encodings can be created by specifying an `id` and `suffix` string: - -```kotlin -val encoding = Encoding(id = 123, suffix = "example suffix") -``` - ## Session-managed declarations Up until 0.11.0, it was up to the user to keep track of their variable declarations to keep them alive, because once the variable declarations were garbage collected, the declarations were closed. This was because each Kotlin variable declaration is associated with a native Rust instance, and in order to avoid leaking the memory of that Rust instance, it was necessary to free it upon dropping the declaration instance. However, this behavior could be counterintuitive, as users were expecting the declaration to keep running despite losing track of the reference to it. @@ -85,14 +79,16 @@ In this release we introduce a change in which any session declaration is intern For instance: ```kotlin -val subscriber = session.declareSubscriber("A/B/C".intoKeyExpr(), +val keyExprA = "A/B/C".intoKeyExpr().getOrThrow() +val subscriber = session.declareSubscriber(keyExprA, callback = { sample -> println("Receiving sample on 'A/B/C': ${sample.payload}") }).getOrThrow() -session.declareSubscriber("A/C/D".intoKeyExpr(), - callback = { sample -> println("Receiving sample on 'A/C/D': ${sample.payload}") }) // No variable is associated to the declared session, on 0.11.0 it would have been instantanely dropped +val keyExprB = "A/C/D".intoKeyExpr().getOrThrow() +session.declareSubscriber(keyExprB, + callback = { sample -> println("Receiving sample on 'A/C/D': ${sample.payload}") }) // No variable is associated to the declared session, on 0.11.0 it would have been instantly dropped ``` -Therfore, when receiving a 'hello' message on `A/**` we would still see: +Therefore, when receiving a 'hello' message on `A/**` we would still see: ``` >> Receiving sample on 'A/B/C': hello @@ -160,7 +156,7 @@ Changes: ## Reliability -The `Reliability` config parameter used on when declaring a subscriber, has been moved. It now must be specified when declaring a `Publisher` or when performing a `Put` or a `Delete` operaton. +The `Reliability` config parameter used on when declaring a subscriber, has been moved. It now must be specified when declaring a `Publisher` or when performing a `Put` or a `Delete` operation. ## Logging @@ -202,202 +198,101 @@ We have created a new abstraction with the name of `ZBytes`. This class represen - `Value` is replaced by the combination of `ZBytes` and `Encoding`. - Replacing `ByteArray` to represent payloads -With `ZBytes` we have also introduced a Serialization and Deserialization for conveinent conversion between `ZBytes` and Kotlin types. +With `ZBytes` we have also introduced a Serialization and Deserialization for convenient conversion between `ZBytes` and Kotlin types. -### Serialization +### Serialization & Deserialization We can serialize primitive types into a `ZBytes` instance, that is, converting the data into bytes processed by the zenoh network: #### Primitive types -The following types support serialization: +(De)Serialization is supported by the following primitive types: - * Numeric: `Byte`, `Short`, `Int`, `Long`, `Float` and `Double`. + * Numeric: `Byte`, `Short`, `Int`, `Long`, `Float`, `Double`, `UByte`, `UShort`, `UInt` and `ULong`. * `String` * `ByteArray` - For the primitive types, there are three ways to serialize them into a `ZBytes`, for instance let's suppose - we want to serialize an `Int`: - - * using the `into()` syntax: - ```kotlin - val exampleInt: Int = 256 - val zbytes: ZBytes = exampleInt.into() - ``` - - * using the `from()` syntax: - ```kotlin - val exampleInt: Int = 256 - val zbytes: ZBytes = ZBytes.from(exampleInt) - ``` - - * using the serialize syntax: +For instance: ```kotlin val exampleInt: Int = 256 - val zbytes: ZBytes = ZBytes.serialize(exampleInt).getOrThrow() + val zbytes: ZBytes = zSerialize(exampleInt).getOrThrow() + val deserialization = zDeserialize(zbytes).getOrThrow() +check(exampleInt == deserialization) ``` + This approach works as well for the other aforementioned types. - Using `into()` or `from()` guarantees successful serialization for implemented types. - Using `serialize` requires a generic parameter, and returns a Result, i.e. it can fail based in the type passed in and contents of the input parameter. +For serialization, `String` and `ByteArray` the functions `ZBytes::from(string: String)` and `ZBytes::from(bytes: ByteArray)` can be used respectively. Analogously, deserialization, `ZBytes::toString()` and `ZBytes::toByteArray()` can be used. #### Lists Lists are supported, but they must be either: - - List of `Number` : (`Byte`, `Short`, `Int`, `Long`, `Float`, `Double`) + - List of numeric types : (`Byte`, `Short`, `Int`, `Long`, `Float`, `Double`, `UByte`, `UShort`, `UInt` and `ULong`) - List of `String` - List of `ByteArray` - - List of `IntoZBytes` + - List of another supported type The serialize syntax must be used: ```kotlin val myList = listOf(1, 2, 5, 8, 13, 21) - val zbytes = ZBytes.serialize>(myList).getOrThrow() + val zbytes = zSerialize>(myList).getOrThrow() + val outputList = zDeserialize>(zbytes).getOrThrow() + check(myList == outputList) ``` #### Maps Maps are supported as well, with the restriction that their inner types must supported primitives: - - `Number` + - Numeric types - `String` - `ByteArray` - - `IntoZBytes` + - Map of another supported types ```kotlin val myMap: Map = mapOf("foo" to 1, "bar" to 2) - val zbytes = ZBytes.serialize>(myMap).getOrThrow() + val zbytes = zSerialize>(myMap).getOrThrow() + val outputMap = zDeserialize>(zbytes).getOrThrow() + output(myMap == outputMap) ``` - ### Deserialization +#### Pair & Triple - #### Primitive types - - * Numeric: `Byte`, `Short`, `Int`, `Long`, `Float` and `Double` - * `String` - * `ByteArray` - - Example: - - For these primitive types, you can use the functions `to`, that is - - `toByte` - - `toShort` - - `toInt` - - `toLong` - - `toDouble` - - `toString` - - `toByteArray` - - For instance, for an Int: - ```kotlin - val example: Int = 256 - val zbytes: ZBytes = exampleInt.into() - val deserializedInt = zbytes.toInt() - ``` - - Alternatively, the deserialize syntax can be used as well: - ```kotlin - val exampleInt: Int = 256 - val zbytes: ZBytes = exampleInt.into() - val deserializedInt = zbytes.deserialize().getOrThrow() - ``` - - #### Lists - - Lists are supported, but they must be deserialized into inner primitive types: - - List of `Number` (`Byte`, `Short`, `Int`, `Long`, `Float` or `Double`) - - List of `String` - - List of `ByteArray` - - To deserialize into a list, use the deserialize syntax as follows: - ```kotlin - val inputList = listOf("sample1", "sample2", "sample3") - payload = ZBytes.serialize(inputList).getOrThrow() - val outputList = payload.deserialize>().getOrThrow() - ``` - - #### Maps - - Maps are supported as well, with the restriction that their inner types must be one of the following: - - `Number` - - `String` - - `ByteArray` - - ```kotlin - val inputMap = mapOf("key1" to "value1", "key2" to "value2", "key3" to "value3") - payload = ZBytes.serialize(inputMap).getOrThrow() - val outputMap = payload.deserialize>().getOrThrow() - check(inputMap == outputMap) - ``` - - ### Custom serialization and deserialization - - #### Serialization - - For a user defined class, the class must implement the `IntoZBytes` interface. - For instance: - - ```kotlin - class Foo(val content: String) : IntoZBytes { - - /*Inherits: IntoZBytes*/ - override fun into(): ZBytes = content.into() - } - ``` - - This way, we can do: - ```kotlin - val foo = Foo("bar") - val serialization = ZBytes.serialize(foo).getOrThrow() - ``` - - Implementing the `IntoZBytes` interface on a class allows serializing lists and maps of that type, for instance: - ```kotlin - val list = listOf(Foo("bar"), Foo("buz"), Foo("fizz")) - val zbytes = ZBytes.serialize>(list) - ``` - - #### Deserialization - - Regarding deserialization for custom objects, for the time being (this API will be expanded to - provide further utilities) you need to manually convert the ZBytes into the type you want. - - ```kotlin - val inputFoo = Foo("example") - payload = ZBytes.serialize(inputFoo).getOrThrow() - val outputFoo = Foo.from(payload) - check(inputFoo == outputFoo) - - // List of Foo. - val inputListFoo = inputList.map { value -> Foo(value) } - payload = ZBytes.serialize>(inputListFoo).getOrThrow() - val outputListFoo = payload.deserialize>().getOrThrow().map { zbytes -> Foo.from(zbytes) } - check(inputListFoo == outputListFoo) - - // Map of Foo. - val inputMapFoo = inputMap.map { (k, v) -> Foo(k) to Foo(v) }.toMap() - payload = ZBytes.serialize>(inputMapFoo).getOrThrow() - val outputMapFoo = payload.deserialize>().getOrThrow() - .map { (key, value) -> Foo.from(key) to Foo.from(value) }.toMap() - check(inputMapFoo == outputMapFoo) - ``` +Similarly, +- Pair: +```kotlin +val input: Pair = Pair("one", 1) +val zbytes = zSerialize(input).getOrThrow() +val output: Pair = zDeserialize(zbytes).getOrThrow() +check(input == output) +``` - ##### Deserialization functions: +- Triple: +```kotlin +val input: Triple = Triple("one", 1, true) +val zbytes = zSerialize(input).getOrThrow() +val output: Triple = zDeserialize(zbytes).getOrThrow() +check(input == output) +``` - As an alternative, the `deserialize` function admits an argument which by default is an emptyMap, consisting - of a `Map>` map. +#### Parameterized types combinations - For instance, the previous implementation of our example Foo class. - We could provide directly the deserialization function as follows: +Combinations of all the above types is supported. For instance: - ```kotlin - fun deserializeFoo(zbytes: ZBytes): Foo { - return Foo(zbytes.toString()) - } +- List of lists +```kotlin +val input: List> = listOf(listOf(1, 2, 3)) +val zbytes = zSerialize(input).getOrThrow() +val output = zDeserialize>>(zbytes).getOrThrow() +check(input == output) +``` - val foo = Foo("bar") - val zbytes = ZBytes.serialize(foo) - val deserialization = zbytes.deserialize(mapOf(typeOf() to ::deserializeFoo)).getOrThrow() - ``` +- List of maps +```kotlin +val input: List> = listOf(mapOf("a" to 1, "b" to 2)) +val zbytes = zSerialize(input).getOrThrow() +val output = zDeserialize>>(zbytes).getOrThrow() +check(input == output) +``` ## Reply handling