From fd915356f095a04c988318917af52536503ea4ad Mon Sep 17 00:00:00 2001 From: hoangchungk53qx1 Date: Fri, 6 Oct 2023 15:14:10 +0700 Subject: [PATCH 1/8] add safeCast operator --- CHANGELOG.md | 4 +++ README.md | 33 ++++++++++++++++++- .../kotlin/com/hoc081098/flowext/cast.kt | 6 ++++ .../kotlin/com/hoc081098/flowext/CastTest.kt | 29 ++++++++++++++++ .../com/hoc081098/flowext/internal/Lock.kt | 2 +- 5 files changed, 72 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e35c84e..b8e69145 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] - TODO +### Added + +- Add `Flow.safeCast` operator. + ### Changed - Update dependencies diff --git a/README.md b/README.md index 1390197b..69aab29c 100644 --- a/README.md +++ b/README.md @@ -432,7 +432,7 @@ timer: kotlin.Unit ---- -#### cast / castNotNull / castNullable +#### cast / castNotNull / castNullable / safeCast - Similar to [RxJava cast](http://reactivex.io/RxJava/3.x/javadoc/io/reactivex/rxjava3/core/Flowable.html#cast-java.lang.Class-) @@ -487,6 +487,37 @@ castNotNull: 3 ---- + +##### safeCast + +Adapt this `Flow<*>` to be a `Flow`. + +At the collection time, converts a Flow<*> to a Flow, if not consistent with R, returns null. + +```kotlin +flowOf(1, 2, 3, "Kotlin", null) + .castSafely() + .collect { v: Int? -> + if (v != null) { + println("safeCast: $v") + } else { + println("Null value encountered.") + } + } +``` + +Output: + +```none +safeCast: 1 +safeCast: 2 +safeCast: 3 +Null value encountered. +Null value encountered. +``` + +---- + #### concatWith - Similar to [RxJS concatWith](https://rxjs.dev/api/operators/concatWith) diff --git a/src/commonMain/kotlin/com/hoc081098/flowext/cast.kt b/src/commonMain/kotlin/com/hoc081098/flowext/cast.kt index d3da3f96..97f56710 100644 --- a/src/commonMain/kotlin/com/hoc081098/flowext/cast.kt +++ b/src/commonMain/kotlin/com/hoc081098/flowext/cast.kt @@ -53,3 +53,9 @@ public inline fun Flow.castNotNull(): Flow = map { it!! */ @Suppress("NOTHING_TO_INLINE") public inline fun Flow.castNullable(): Flow = this + +/** + * Adapt this `Flow<*>` to be a `Flow`. + */ +@Suppress("NOTHING_TO_INLINE") +public inline fun Flow<*>.safeCast(): Flow = map { it as? R } diff --git a/src/commonTest/kotlin/com/hoc081098/flowext/CastTest.kt b/src/commonTest/kotlin/com/hoc081098/flowext/CastTest.kt index f663e32c..3e219ac8 100644 --- a/src/commonTest/kotlin/com/hoc081098/flowext/CastTest.kt +++ b/src/commonTest/kotlin/com/hoc081098/flowext/CastTest.kt @@ -96,4 +96,33 @@ class CastTest : BaseTest() { val flow = flowOf(1, 2, 3) assertSame(flow.castNullable(), flow) } + + @Test + fun testSafeCastSuccess() = runTest { + assertIs>( + flowOf(1, 2, 3, "hello").safeCast(), + ) + + assertIs>( + flowOf(1, 2, 3) + .safeCast(), + ) + .test( + listOf( + Event.Value(1), + Event.Value(2), + Event.Value(3), + Event.Complete, + ), + ) + } + + @Test + fun testSafeCast() { + val stringFlow: Flow = flowOf("Hello", 42, "World", 123, "Kotlin").safeCast() + assertIs>(stringFlow) + + val intFlow: Flow = flowOf(1, 2, 3, null).safeCast() + assertIs>(intFlow) + } } diff --git a/src/pthreadAndroidMain/kotlin/com/hoc081098/flowext/internal/Lock.kt b/src/pthreadAndroidMain/kotlin/com/hoc081098/flowext/internal/Lock.kt index 2bb58207..0cdb1457 100644 --- a/src/pthreadAndroidMain/kotlin/com/hoc081098/flowext/internal/Lock.kt +++ b/src/pthreadAndroidMain/kotlin/com/hoc081098/flowext/internal/Lock.kt @@ -1,4 +1,4 @@ -/* + /* * MIT License * * Copyright (c) 2021-2023 Petrus Nguyễn Thái Học From acf21a4239a29481fee8a620c9c51c5f93f0b519 Mon Sep 17 00:00:00 2001 From: hoangchungk53qx1 Date: Fri, 6 Oct 2023 15:14:58 +0700 Subject: [PATCH 2/8] add safeCast operator --- .../kotlin/com/hoc081098/flowext/internal/Lock.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pthreadAndroidMain/kotlin/com/hoc081098/flowext/internal/Lock.kt b/src/pthreadAndroidMain/kotlin/com/hoc081098/flowext/internal/Lock.kt index 0cdb1457..2bb58207 100644 --- a/src/pthreadAndroidMain/kotlin/com/hoc081098/flowext/internal/Lock.kt +++ b/src/pthreadAndroidMain/kotlin/com/hoc081098/flowext/internal/Lock.kt @@ -1,4 +1,4 @@ - /* +/* * MIT License * * Copyright (c) 2021-2023 Petrus Nguyễn Thái Học From dac3c48c194a6a6e3940ff606b2338a67183413e Mon Sep 17 00:00:00 2001 From: hoangchung <52132635+hoangchungk53qx1@users.noreply.github.com> Date: Fri, 6 Oct 2023 15:41:04 +0700 Subject: [PATCH 3/8] Update README.md --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 69aab29c..a64cdee8 100644 --- a/README.md +++ b/README.md @@ -122,9 +122,10 @@ dependencies { - Intermediate operators - [`bufferCount`](#buffercount) - [`combine`](#combine) - - [`cast`](#cast--castnotnull--castnullable) - - [`castNotNull`](#cast--castnotnull--castnullable) - - [`castNullable`](#cast--castnotnull--castnullable) + - [`cast`](#cast--castnotnull--castnullable--safeCast) + - [`castNotNull`](#cast--castnotnull--castnullable--safeCast) + - [`castNullable`](#cast--castnotnull--castnullable--safeCast) + - [`safeCast`](#cast--castnotnull--castnullable--safeCast) - [`concatWith`](#concatwith) - [`startWith`](#startwith) - [`flatMapFirst`](#flatmapfirst--exhaustmap) From 98643a5813e50ffe8c1cea2de4d2cb4c703f51db Mon Sep 17 00:00:00 2001 From: hoangchung <52132635+hoangchungk53qx1@users.noreply.github.com> Date: Fri, 6 Oct 2023 15:45:22 +0700 Subject: [PATCH 4/8] Update README.md update docs --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a64cdee8..5155700d 100644 --- a/README.md +++ b/README.md @@ -497,7 +497,7 @@ At the collection time, converts a Flow<*> to a Flow, if not consistent with ```kotlin flowOf(1, 2, 3, "Kotlin", null) - .castSafely() + .safeCast() .collect { v: Int? -> if (v != null) { println("safeCast: $v") From 4bb3e8fa39033108089b5aa7748b3c668c6ab1c1 Mon Sep 17 00:00:00 2001 From: hoangchungk53qx1 Date: Sat, 7 Oct 2023 00:32:51 +0700 Subject: [PATCH 5/8] resolve CastTest.kt and README.md --- CHANGELOG.md | 4 ++-- README.md | 14 ++++------- .../kotlin/com/hoc081098/flowext/CastTest.kt | 23 ++++++++++++++++--- 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8e69145..fdd48f66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,12 @@ ## [Unreleased] - TODO +### Changed + ### Added - Add `Flow.safeCast` operator. -### Changed - - Update dependencies - `Gradle` to `8.3`. diff --git a/README.md b/README.md index 5155700d..3f731132 100644 --- a/README.md +++ b/README.md @@ -493,18 +493,12 @@ castNotNull: 3 Adapt this `Flow<*>` to be a `Flow`. -At the collection time, converts a Flow<*> to a Flow, if not consistent with R, returns null. +At the collection time, if this `Flow` has any value that is not an instance of R, null will be emitted. ```kotlin flowOf(1, 2, 3, "Kotlin", null) .safeCast() - .collect { v: Int? -> - if (v != null) { - println("safeCast: $v") - } else { - println("Null value encountered.") - } - } + .collect { v: Int? -> println("safeCast: $v") } ``` Output: @@ -513,8 +507,8 @@ Output: safeCast: 1 safeCast: 2 safeCast: 3 -Null value encountered. -Null value encountered. +safeCast: null +safeCast: null ``` ---- diff --git a/src/commonTest/kotlin/com/hoc081098/flowext/CastTest.kt b/src/commonTest/kotlin/com/hoc081098/flowext/CastTest.kt index 3e219ac8..c47c9e7d 100644 --- a/src/commonTest/kotlin/com/hoc081098/flowext/CastTest.kt +++ b/src/commonTest/kotlin/com/hoc081098/flowext/CastTest.kt @@ -28,11 +28,13 @@ import com.hoc081098.flowext.utils.BaseTest import com.hoc081098.flowext.utils.assertFailsWith import com.hoc081098.flowext.utils.test import kotlin.test.Test +import kotlin.test.assertContentEquals import kotlin.test.assertIs import kotlin.test.assertSame import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.toList @ExperimentalCoroutinesApi class CastTest : BaseTest() { @@ -99,12 +101,12 @@ class CastTest : BaseTest() { @Test fun testSafeCastSuccess() = runTest { - assertIs>( + assertIs>( flowOf(1, 2, 3, "hello").safeCast(), ) - assertIs>( - flowOf(1, 2, 3) + assertIs>( + flowOf(1, 2, 3, "kotlin", null) .safeCast(), ) .test( @@ -112,6 +114,8 @@ class CastTest : BaseTest() { Event.Value(1), Event.Value(2), Event.Value(3), + Event.Value(null), + Event.Value(null), Event.Complete, ), ) @@ -122,7 +126,20 @@ class CastTest : BaseTest() { val stringFlow: Flow = flowOf("Hello", 42, "World", 123, "Kotlin").safeCast() assertIs>(stringFlow) + kotlinx.coroutines.test.runTest { + assertContentEquals( + listOf("Hello", null, "World", null, "Kotlin"), + stringFlow.toList(), + ) + } val intFlow: Flow = flowOf(1, 2, 3, null).safeCast() assertIs>(intFlow) + + kotlinx.coroutines.test.runTest { + assertContentEquals( + listOf(1, 2, 3, null), + intFlow.toList(), + ) + } } } From ec195e7e425890854c4a9fef5620221c477bd03e Mon Sep 17 00:00:00 2001 From: hoangchungk53qx1 Date: Sat, 7 Oct 2023 00:56:11 +0700 Subject: [PATCH 6/8] resolve CastTest.kt and README.md --- CHANGELOG.md | 6 +---- .../kotlin/com/hoc081098/flowext/cast.kt | 2 ++ .../kotlin/com/hoc081098/flowext/CastTest.kt | 23 ++++++++----------- 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fdd48f66..7b88df3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,6 @@ ### Changed -### Added - -- Add `Flow.safeCast` operator. - - Update dependencies - `Gradle` to `8.3`. @@ -15,7 +11,7 @@ - Add `Flow.ignoreElements` operator. - Add `Flow.scanWith` operator. - +- Add `Flow.safeCast` operator. ## [0.7.0] ~ [0.7.1] - Jul 31, 2023 ### Changed diff --git a/src/commonMain/kotlin/com/hoc081098/flowext/cast.kt b/src/commonMain/kotlin/com/hoc081098/flowext/cast.kt index 97f56710..6bf35aec 100644 --- a/src/commonMain/kotlin/com/hoc081098/flowext/cast.kt +++ b/src/commonMain/kotlin/com/hoc081098/flowext/cast.kt @@ -56,6 +56,8 @@ public inline fun Flow.castNullable(): Flow = this /** * Adapt this `Flow<*>` to be a `Flow`. + * Add At the collection time, if this [Flow] has any value that is not an instance of R, + * null will be emitted */ @Suppress("NOTHING_TO_INLINE") public inline fun Flow<*>.safeCast(): Flow = map { it as? R } diff --git a/src/commonTest/kotlin/com/hoc081098/flowext/CastTest.kt b/src/commonTest/kotlin/com/hoc081098/flowext/CastTest.kt index c47c9e7d..432fa6c5 100644 --- a/src/commonTest/kotlin/com/hoc081098/flowext/CastTest.kt +++ b/src/commonTest/kotlin/com/hoc081098/flowext/CastTest.kt @@ -122,24 +122,21 @@ class CastTest : BaseTest() { } @Test - fun testSafeCast() { + fun testSafeCast() = runTest{ val stringFlow: Flow = flowOf("Hello", 42, "World", 123, "Kotlin").safeCast() assertIs>(stringFlow) - kotlinx.coroutines.test.runTest { - assertContentEquals( - listOf("Hello", null, "World", null, "Kotlin"), - stringFlow.toList(), - ) - } + assertContentEquals( + listOf("Hello", null, "World", null, "Kotlin"), + stringFlow.toList(), + ) + val intFlow: Flow = flowOf(1, 2, 3, null).safeCast() assertIs>(intFlow) - kotlinx.coroutines.test.runTest { - assertContentEquals( - listOf(1, 2, 3, null), - intFlow.toList(), - ) - } + assertContentEquals( + listOf(1, 2, 3, null), + intFlow.toList(), + ) } } From 281b442d23ea10c4010013342f4fd78f5e0a2954 Mon Sep 17 00:00:00 2001 From: hoangchungk53qx1 Date: Sat, 7 Oct 2023 00:57:26 +0700 Subject: [PATCH 7/8] resolve CastTest.kt and README.md --- src/commonTest/kotlin/com/hoc081098/flowext/CastTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commonTest/kotlin/com/hoc081098/flowext/CastTest.kt b/src/commonTest/kotlin/com/hoc081098/flowext/CastTest.kt index 432fa6c5..0b9e5132 100644 --- a/src/commonTest/kotlin/com/hoc081098/flowext/CastTest.kt +++ b/src/commonTest/kotlin/com/hoc081098/flowext/CastTest.kt @@ -122,7 +122,7 @@ class CastTest : BaseTest() { } @Test - fun testSafeCast() = runTest{ + fun testSafeCast() = runTest { val stringFlow: Flow = flowOf("Hello", 42, "World", 123, "Kotlin").safeCast() assertIs>(stringFlow) From c0bdf9e755e53fc04d103a8a42e498d56c2de02d Mon Sep 17 00:00:00 2001 From: hoangchungk53qx1 Date: Sat, 7 Oct 2023 01:00:10 +0700 Subject: [PATCH 8/8] resolve CastTest.kt and README.md --- src/commonMain/kotlin/com/hoc081098/flowext/cast.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commonMain/kotlin/com/hoc081098/flowext/cast.kt b/src/commonMain/kotlin/com/hoc081098/flowext/cast.kt index 6bf35aec..806313cf 100644 --- a/src/commonMain/kotlin/com/hoc081098/flowext/cast.kt +++ b/src/commonMain/kotlin/com/hoc081098/flowext/cast.kt @@ -56,7 +56,7 @@ public inline fun Flow.castNullable(): Flow = this /** * Adapt this `Flow<*>` to be a `Flow`. - * Add At the collection time, if this [Flow] has any value that is not an instance of R, + * At the collection time, if this [Flow] has any value that is not an instance of R, * null will be emitted */ @Suppress("NOTHING_TO_INLINE")