diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fbf3af1..2f12af3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - `skipUntil`, `dropUntil`. - `pairwise`. - `NeverFlow` interface and `NeverFlow.Companion` object. + - `cast`, `castNotNull`, `castNullable`. - Refactor - `neverFlow()` now returns `NeverFlow`. diff --git a/README.md b/README.md index 769fc82a..a108174e 100644 --- a/README.md +++ b/README.md @@ -31,10 +31,23 @@ ## Author: [Petrus Nguyễn Thái Học](https://github.com/hoc081098) ## Buy me a coffee + Liked some of my work? Buy me a coffee (or more likely a beer) [!["Buy Me A Coffee"](https://cdn.buymeacoffee.com/buttons/default-orange.png)](https://www.buymeacoffee.com/hoc081098) +## Supported targets + +- `android` +- `jvm` +- `js` (`IR` and `LEGACY`) +- `iosArm64`, `iosArm32`, `iosX64`, `iosSimulatorArm64` +- `watchosArm32`, `watchosArm64`, `watchosX64`, `watchosX86`, `watchosSimulatorArm64` +- `tvosX64`, `tvosSimulatorArm64`, `tvosArm64`. +- `macosX64`, `macosArm64` +- `mingwX64` +- `linuxX64` + ## API ### 0.x release docs: https://hoc081098.github.io/FlowExt/docs/0.x @@ -55,6 +68,9 @@ Liked some of my work? Buy me a coffee (or more likely a beer) - [`timer`](#timer) - Intermediate operators - [`bufferCount`](#bufferCount) + - [`cast`](#cast--castnotNull--castnullable) + - [`castNotNull`](#cast--castnotNull--castnullable) + - [`castNullable`](#cast--castnotNull--castnullable) - [`concatWith`](#concatWith) - [`startWith`](#startWith) - [`flatMapFirst`](#flatmapfirst--exhaustmap) @@ -101,7 +117,8 @@ Liked some of my work? Buy me a coffee (or more likely a beer) #### flowFromSuspend -- Similar to [RxJava fromCallable](http://reactivex.io/RxJava/3.x/javadoc/io/reactivex/rxjava3/core/Flowable.html#fromCallable-java.util.concurrent.Callable-) +- Similar + to [RxJava fromCallable](http://reactivex.io/RxJava/3.x/javadoc/io/reactivex/rxjava3/core/Flowable.html#fromCallable-java.util.concurrent.Callable-) #### interval @@ -129,6 +146,11 @@ Liked some of my work? Buy me a coffee (or more likely a beer) - ReactiveX docs: http://reactivex.io/documentation/operators/timer.html - Similar to [RxJS timer](https://rxjs.dev/api/index/function/timer) +#### cast / castNotNull / castNullable + +- Similar + to [RxJava cast](http://reactivex.io/RxJava/3.x/javadoc/io/reactivex/rxjava3/core/Flowable.html#cast-java.lang.Class-) + #### concatWith - Similar to [RxJS concatWith](https://rxjs.dev/api/operators/concatWith) @@ -153,7 +175,8 @@ Liked some of my work? Buy me a coffee (or more likely a beer) #### flatMapConcatEager -- Similar to [RxJava concatMapEager](http://reactivex.io/RxJava/3.x/javadoc/io/reactivex/rxjava3/core/Flowable.html#concatMapEager-io.reactivex.rxjava3.functions.Function-) +- Similar + to [RxJava concatMapEager](http://reactivex.io/RxJava/3.x/javadoc/io/reactivex/rxjava3/core/Flowable.html#concatMapEager-io.reactivex.rxjava3.functions.Function-) #### mapTo @@ -187,7 +210,8 @@ Liked some of my work? Buy me a coffee (or more likely a beer) - ReactiveX docs: https://reactivex.io/documentation/operators/skipuntil.html - Similar to [RxJS skipUntil](https://rxjs.dev/api/index/function/skipUntil) -- Similar to [RxJava skipUntil](http://reactivex.io/RxJava/3.x/javadoc/io/reactivex/rxjava3/core/Flowable.html#skipUntil-org.reactivestreams.Publisher-) +- Similar + to [RxJava skipUntil](http://reactivex.io/RxJava/3.x/javadoc/io/reactivex/rxjava3/core/Flowable.html#skipUntil-org.reactivestreams.Publisher-) #### takeUntil @@ -225,23 +249,6 @@ implementation("io.github.hoc081098:FlowExt:0.3.0") implementation("io.github.hoc081098:FlowExt-jvm:0.3.0") ``` -### Native binaries - -```groovy -implementation("io.github.hoc081098:FlowExt-iosx64:0.3.0") -implementation("io.github.hoc081098:FlowExt-iosarm64:0.3.0") -implementation("io.github.hoc081098:FlowExt-iosarm32:0.3.0") -implementation("io.github.hoc081098:FlowExt-watchosx86:0.3.0") -implementation("io.github.hoc081098:FlowExt-watchosx64:0.3.0") -implementation("io.github.hoc081098:FlowExt-watchosarm64:0.3.0") -implementation("io.github.hoc081098:FlowExt-watchosarm32:0.3.0") -implementation("io.github.hoc081098:FlowExt-tvosx64:0.3.0") -implementation("io.github.hoc081098:FlowExt-tvosxarm64:0.3.0") -implementation("io.github.hoc081098:FlowExt-macosx64:0.3.0") -implementation("io.github.hoc081098:FlowExt-mingwx64:0.3.0") -implementation("io.github.hoc081098:FlowExt-linuxx64:0.3.0") -``` - ### Snapshot Snapshots of the development version are available in Sonatype's snapshots repository. diff --git a/api/FlowExt.api b/api/FlowExt.api index 8f3e334e..1d216a0c 100644 --- a/api/FlowExt.api +++ b/api/FlowExt.api @@ -3,6 +3,10 @@ public final class com/hoc081098/flowext/BufferCountKt { public static final fun bufferCount (Lkotlinx/coroutines/flow/Flow;II)Lkotlinx/coroutines/flow/Flow; } +public final class com/hoc081098/flowext/CastKt { + public static final fun castNullable (Lkotlinx/coroutines/flow/Flow;)Lkotlinx/coroutines/flow/Flow; +} + public final class com/hoc081098/flowext/ConcatKt { public static final fun concat (Ljava/lang/Iterable;)Lkotlinx/coroutines/flow/Flow; public static final fun concat (Lkotlin/sequences/Sequence;)Lkotlinx/coroutines/flow/Flow; diff --git a/kotlin-js-store/yarn.lock b/kotlin-js-store/yarn.lock index 150088f3..6f2f6759 100644 --- a/kotlin-js-store/yarn.lock +++ b/kotlin-js-store/yarn.lock @@ -85,10 +85,10 @@ chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chokidar@3.5.3: - version "3.5.3" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" - integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== +chokidar@3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" + integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== dependencies: anymatch "~3.1.2" braces "~3.0.2" @@ -126,10 +126,10 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -debug@4.3.3: - version "4.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== +debug@4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" + integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== dependencies: ms "2.1.2" @@ -205,10 +205,10 @@ glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" -glob@7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" - integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== +glob@7.1.7: + version "7.1.7" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" + integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -318,32 +318,32 @@ minimatch@3.0.4, minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" -mocha@9.2.1: - version "9.2.1" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-9.2.1.tgz#a1abb675aa9a8490798503af57e8782a78f1338e" - integrity sha512-T7uscqjJVS46Pq1XDXyo9Uvey9gd3huT/DD9cYBb4K2Xc/vbKRPUWK067bxDQRK0yIz6Jxk73IrnimvASzBNAQ== +mocha@9.1.2: + version "9.1.2" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-9.1.2.tgz#93f53175b0f0dc4014bd2d612218fccfcf3534d3" + integrity sha512-ta3LtJ+63RIBP03VBjMGtSqbe6cWXRejF9SyM9Zyli1CKZJZ+vfCTj3oW24V7wAphMJdpOFLoMI3hjJ1LWbs0w== dependencies: "@ungap/promise-all-settled" "1.1.2" ansi-colors "4.1.1" browser-stdout "1.3.1" - chokidar "3.5.3" - debug "4.3.3" + chokidar "3.5.2" + debug "4.3.2" diff "5.0.0" escape-string-regexp "4.0.0" find-up "5.0.0" - glob "7.2.0" + glob "7.1.7" growl "1.10.5" he "1.2.0" js-yaml "4.1.0" log-symbols "4.1.0" minimatch "3.0.4" ms "2.1.3" - nanoid "3.2.0" + nanoid "3.1.25" serialize-javascript "6.0.0" strip-json-comments "3.1.1" supports-color "8.1.1" which "2.0.2" - workerpool "6.2.0" + workerpool "6.1.5" yargs "16.2.0" yargs-parser "20.2.4" yargs-unparser "2.0.0" @@ -358,10 +358,10 @@ ms@2.1.3: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -nanoid@3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.2.0.tgz#62667522da6673971cca916a6d3eff3f415ff80c" - integrity sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA== +nanoid@3.1.25: + version "3.1.25" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.25.tgz#09ca32747c0e543f0e1814b7d3793477f9c8e152" + integrity sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q== normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" @@ -435,10 +435,10 @@ serialize-javascript@6.0.0: dependencies: randombytes "^2.1.0" -source-map-support@0.5.21: - version "0.5.21" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" - integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== +source-map-support@0.5.20: + version "0.5.20" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" + integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" @@ -497,10 +497,10 @@ which@2.0.2: dependencies: isexe "^2.0.0" -workerpool@6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.0.tgz#827d93c9ba23ee2019c3ffaff5c27fccea289e8b" - integrity sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A== +workerpool@6.1.5: + version "6.1.5" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.1.5.tgz#0f7cf076b6215fd7e1da903ff6f22ddd1886b581" + integrity sha512-XdKkCK0Zqc6w3iTxLckiuJ81tiD/o5rBE/m+nXpRCB+/Sq4DqkfXZ/x0jW02DG1tGsfUGXbTJyZDP+eu67haSw== wrap-ansi@^7.0.0: version "7.0.0" diff --git a/src/commonMain/kotlin/com/hoc081098/flowext/cast.kt b/src/commonMain/kotlin/com/hoc081098/flowext/cast.kt new file mode 100644 index 00000000..a96f0d98 --- /dev/null +++ b/src/commonMain/kotlin/com/hoc081098/flowext/cast.kt @@ -0,0 +1,55 @@ +/* + * MIT License + * + * Copyright (c) 2021-2022 Petrus Nguyễn Thái Học + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.hoc081098.flowext + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map + +/** + * Adapt this [Flow] to be a `Flow`. + * + * This Flow is wrapped as a `Flow` which checks at run-time that each value event emitted + * by this Flow is also an instance of R. + * + * At the collection time, if this [Flow] has any value that is not an instance of R, + * a [ClassCastException] will be thrown. + */ +@Suppress("NOTHING_TO_INLINE") +public inline fun Flow<*>.cast(): Flow = map { it as R } + +/** + * Adapt this `Flow` to be a `Flow`. + * + * At the collection time, if this [Flow] has any `null` value, + * a [NullPointerException] will be thrown. + */ +@Suppress("NOTHING_TO_INLINE") +public inline fun Flow.castNotNull(): Flow = map { it!! } + +/** + * Adapt this `Flow` to be a `Flow`. + */ +@Suppress("NOTHING_TO_INLINE") +public inline fun Flow.castNullable(): Flow = this diff --git a/src/commonTest/kotlin/com/hoc081098/flowext/CastTest.kt b/src/commonTest/kotlin/com/hoc081098/flowext/CastTest.kt new file mode 100644 index 00000000..06430c26 --- /dev/null +++ b/src/commonTest/kotlin/com/hoc081098/flowext/CastTest.kt @@ -0,0 +1,99 @@ +/* + * MIT License + * + * Copyright (c) 2021-2022 Petrus Nguyễn Thái Học + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.hoc081098.flowext + +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.assertIs +import kotlin.test.assertSame +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOf + +@ExperimentalCoroutinesApi +class CastTest : BaseTest() { + @Test + fun testCastSuccess() = runTest { + assertIs>(flowOf(1, 2, 3).cast()) + + assertIs>( + flowOf(1, 2, 3) + .cast() + ) + .test( + listOf( + Event.Value(1), + Event.Value(2), + Event.Value(3), + Event.Complete + ) + ) + } + + @Test + fun testCastFailure() = runTest { + assertFailsWith( + flowOf(1, 2, 3).cast() + ) + } + + @Test + fun testCastNotNullSuccess() = runTest { + assertIs>( + flowOf(1, 2, 3, null).castNotNull() + ) + + assertIs>( + flowOf(1, 2, 3) + .castNotNull() + ) + .test( + listOf( + Event.Value(1), + Event.Value(2), + Event.Value(3), + Event.Complete + ) + ) + } + + @Test + fun testCastNotNullFailure() = runTest { + assertFailsWith( + flowOf(1, 2, 3, null).castNotNull() + ) + } + + @Test + fun testCastNullable() { + assertIs>(flowOf(1, 2, 3).castNullable()) + assertIs>(flowOf(1, 2, 3, null).castNullable()) + + val flow = flowOf(1, 2, 3) + assertSame(flow.castNullable(), flow) + } +}