mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2025-09-17 14:29:24 +00:00
Compare commits
14 Commits
Author | SHA1 | Date | |
---|---|---|---|
a33ad123f6 | |||
7e14fa2f5c | |||
ba698b41e1 | |||
e76215987e | |||
d1a247af8c | |||
2b7e9534f3 | |||
38521558a1 | |||
100f3d214b | |||
1309867611 | |||
611f64f2e1 | |||
f118ebce6e | |||
59fc90e556 | |||
fb9e4d57fb | |||
960c38b696 |
8
.space.kts
Normal file
8
.space.kts
Normal file
@@ -0,0 +1,8 @@
|
||||
job("Build and run tests") {
|
||||
container(displayName = "Run gradle build", image = "openjdk:11") {
|
||||
kotlinScript { api ->
|
||||
// here can be your complex logic
|
||||
api.gradlew("build")
|
||||
}
|
||||
}
|
||||
}
|
27
.travis.yml
27
.travis.yml
@@ -1,27 +0,0 @@
|
||||
language: android
|
||||
install: true
|
||||
|
||||
os: linux
|
||||
dist: trusty
|
||||
jdk: oraclejdk8
|
||||
|
||||
android:
|
||||
components:
|
||||
- tools
|
||||
- platform-tools
|
||||
- build-tools-30.0.2
|
||||
- android-30
|
||||
- add-on
|
||||
- extra
|
||||
|
||||
before_script:
|
||||
- yes | /usr/local/android-sdk/tools/bin/sdkmanager "build-tools;30.0.2"
|
||||
- yes | /usr/local/android-sdk/tools/bin/sdkmanager "platforms;android-30"
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- stage: build
|
||||
script: ./gradlew build -s -x jvmTest -x jsIrTest -x jsIrBrowserTest -x jsIrNodeTest -x jsLegacyTest -x jsLegacyBrowserTest -x jsLegacyNodeTest
|
||||
# Tests are temporarily disabled on public travis due to the problems of launching
|
||||
# - state: test
|
||||
# script: ./gradlew allTests
|
22
CHANGELOG.md
22
CHANGELOG.md
@@ -1,5 +1,27 @@
|
||||
# Changelog
|
||||
|
||||
## 0.5.16
|
||||
|
||||
* `Versions`
|
||||
* `Coroutines`: `1.5.0` -> `1.5.1`
|
||||
* `Serialization`: `1.2.1` -> `1.2.2`
|
||||
* `Ktor`: `1.6.0` -> `1.6.1`
|
||||
* `Klock`: `2.1.2` -> `2.2.0`
|
||||
* `Core KTX`: `1.5.0` -> `1.6.0`
|
||||
|
||||
## 0.5.15 HOTFIX FOR 0.5.14
|
||||
|
||||
* `Coroutines`
|
||||
* Fixes in `subscribeAsync`
|
||||
|
||||
## 0.5.14 NOT RECOMMENDED
|
||||
|
||||
* `Versions`
|
||||
* `Kotlin`: `1.5.10` -> `1.5.20`
|
||||
* `Coroutines`
|
||||
* `subscribeSafelyWithoutExceptions` got new parameter `onException` by analogue with `safelyWithoutExceptions`
|
||||
* New extensions `Flow#subscribeAsync` and subsequent analogs of `subscribe` with opportunity to set up custom marker
|
||||
|
||||
## 0.5.13
|
||||
|
||||
* `Common`:
|
||||
|
@@ -4,6 +4,8 @@ package dev.inmo.micro_utils.coroutines
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
|
||||
/**
|
||||
* Shortcut for chain if [Flow.onEach] and [Flow.launchIn]
|
||||
@@ -29,9 +31,10 @@ inline fun <T> Flow<T>.subscribeSafely(
|
||||
*/
|
||||
inline fun <T> Flow<T>.subscribeSafelyWithoutExceptions(
|
||||
scope: CoroutineScope,
|
||||
noinline onException: ExceptionHandler<T?> = defaultSafelyWithoutExceptionHandlerWithNull,
|
||||
noinline block: suspend (T) -> Unit
|
||||
) = subscribe(scope) {
|
||||
safelyWithoutExceptions {
|
||||
safelyWithoutExceptions(onException) {
|
||||
block(it)
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,118 @@
|
||||
package dev.inmo.micro_utils.coroutines
|
||||
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.*
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
|
||||
private class SubscribeAsyncReceiver<T>(
|
||||
val scope: CoroutineScope,
|
||||
output: suspend SubscribeAsyncReceiver<T>.(T) -> Unit
|
||||
) {
|
||||
private val dataChannel: Channel<T> = Channel(Channel.UNLIMITED)
|
||||
val channel: SendChannel<T>
|
||||
get() = dataChannel
|
||||
|
||||
init {
|
||||
scope.launchSafelyWithoutExceptions {
|
||||
for (data in dataChannel) {
|
||||
output(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun isEmpty(): Boolean = dataChannel.isEmpty
|
||||
}
|
||||
|
||||
private sealed interface AsyncSubscriptionCommand<T, M> {
|
||||
suspend operator fun invoke(markersMap: MutableMap<M, SubscribeAsyncReceiver<T>>)
|
||||
}
|
||||
private data class AsyncSubscriptionCommandData<T, M>(
|
||||
val data: T,
|
||||
val scope: CoroutineScope,
|
||||
val markerFactory: suspend (T) -> M,
|
||||
val block: suspend (T) -> Unit,
|
||||
val onEmpty: suspend (M) -> Unit
|
||||
) : AsyncSubscriptionCommand<T, M> {
|
||||
override suspend fun invoke(markersMap: MutableMap<M, SubscribeAsyncReceiver<T>>) {
|
||||
val marker = markerFactory(data)
|
||||
markersMap.getOrPut(marker) {
|
||||
SubscribeAsyncReceiver(scope.LinkedSupervisorScope()) {
|
||||
safelyWithoutExceptions { block(it) }
|
||||
if (isEmpty()) {
|
||||
onEmpty(marker)
|
||||
}
|
||||
}
|
||||
}.channel.send(data)
|
||||
}
|
||||
}
|
||||
|
||||
private data class AsyncSubscriptionCommandClearReceiver<T, M>(
|
||||
val marker: M
|
||||
) : AsyncSubscriptionCommand<T, M> {
|
||||
override suspend fun invoke(markersMap: MutableMap<M, SubscribeAsyncReceiver<T>>) {
|
||||
val receiver = markersMap[marker]
|
||||
if (receiver ?.isEmpty() == true) {
|
||||
markersMap.remove(marker)
|
||||
receiver.scope.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <T, M> Flow<T>.subscribeAsync(
|
||||
scope: CoroutineScope,
|
||||
markerFactory: suspend (T) -> M,
|
||||
block: suspend (T) -> Unit
|
||||
): Job {
|
||||
val subscope = scope.LinkedSupervisorScope()
|
||||
val markersMap = mutableMapOf<M, SubscribeAsyncReceiver<T>>()
|
||||
val actor = subscope.actor<AsyncSubscriptionCommand<T, M>>(Channel.UNLIMITED) {
|
||||
it.invoke(markersMap)
|
||||
}
|
||||
|
||||
val job = subscribeSafelyWithoutExceptions(subscope) { data ->
|
||||
val dataCommand = AsyncSubscriptionCommandData(data, subscope, markerFactory, block) { marker ->
|
||||
actor.send(
|
||||
AsyncSubscriptionCommandClearReceiver(marker)
|
||||
)
|
||||
}
|
||||
actor.send(dataCommand)
|
||||
}
|
||||
|
||||
job.invokeOnCompletion { if (subscope.isActive) subscope.cancel() }
|
||||
|
||||
return job
|
||||
}
|
||||
|
||||
inline fun <T, M> Flow<T>.subscribeSafelyAsync(
|
||||
scope: CoroutineScope,
|
||||
noinline markerFactory: suspend (T) -> M,
|
||||
noinline onException: ExceptionHandler<Unit> = defaultSafelyExceptionHandler,
|
||||
noinline block: suspend (T) -> Unit
|
||||
) = subscribeAsync(scope, markerFactory) {
|
||||
safely(onException) {
|
||||
block(it)
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <T, M> Flow<T>.subscribeSafelyWithoutExceptionsAsync(
|
||||
scope: CoroutineScope,
|
||||
noinline markerFactory: suspend (T) -> M,
|
||||
noinline onException: ExceptionHandler<T?> = defaultSafelyWithoutExceptionHandlerWithNull,
|
||||
noinline block: suspend (T) -> Unit
|
||||
) = subscribeAsync(scope, markerFactory) {
|
||||
safelyWithoutExceptions(onException) {
|
||||
block(it)
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <T, M> Flow<T>.subscribeSafelySkippingExceptionsAsync(
|
||||
scope: CoroutineScope,
|
||||
noinline markerFactory: suspend (T) -> M,
|
||||
noinline block: suspend (T) -> Unit
|
||||
) = subscribeAsync(scope, markerFactory) {
|
||||
safelyWithoutExceptions({ /* do nothing */}) {
|
||||
block(it)
|
||||
}
|
||||
}
|
@@ -7,14 +7,14 @@ android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
org.gradle.jvmargs=-Xmx2g
|
||||
|
||||
kotlin_version=1.5.10
|
||||
kotlin_coroutines_version=1.5.0
|
||||
kotlin_serialisation_core_version=1.2.1
|
||||
kotlin_version=1.5.20
|
||||
kotlin_coroutines_version=1.5.1
|
||||
kotlin_serialisation_core_version=1.2.2
|
||||
kotlin_exposed_version=0.32.1
|
||||
|
||||
ktor_version=1.6.0
|
||||
ktor_version=1.6.1
|
||||
|
||||
klockVersion=2.1.2
|
||||
klockVersion=2.2.0
|
||||
|
||||
github_release_plugin_version=2.2.12
|
||||
|
||||
@@ -22,14 +22,14 @@ uuidVersion=0.3.0
|
||||
|
||||
# ANDROID
|
||||
|
||||
core_ktx_version=1.5.0
|
||||
core_ktx_version=1.6.0
|
||||
androidx_recycler_version=1.2.1
|
||||
appcompat_version=1.3.0
|
||||
|
||||
android_minSdkVersion=19
|
||||
android_compileSdkVersion=30
|
||||
android_buildToolsVersion=30.0.3
|
||||
dexcount_version=2.0.0
|
||||
dexcount_version=2.1.0-RC01
|
||||
junit_version=4.12
|
||||
test_ext_junit_version=1.1.2
|
||||
espresso_core=3.3.0
|
||||
@@ -45,5 +45,5 @@ dokka_version=1.4.32
|
||||
# Project data
|
||||
|
||||
group=dev.inmo
|
||||
version=0.5.13
|
||||
android_code_version=54
|
||||
version=0.5.16
|
||||
android_code_version=57
|
||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
Reference in New Issue
Block a user