mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2025-10-11 18:30:26 +00:00
Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
14e666f18d | |||
cce914091c | |||
d7cd3db8e2 | |||
0d8f844314 | |||
abd0cb2031 | |||
79ef03ed0c | |||
a3087cb650 | |||
9acb9af338 | |||
0c9283eb87 | |||
493d838201 | |||
4f00eaa6d4 |
22
CHANGELOG.md
22
CHANGELOG.md
@@ -1,5 +1,27 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.4.20
|
||||||
|
|
||||||
|
* `Serialization`
|
||||||
|
* `Encapsulator`:
|
||||||
|
* Has been created
|
||||||
|
|
||||||
|
## 0.4.19
|
||||||
|
|
||||||
|
* `Coroutines`:
|
||||||
|
* New extension `Iterable<Deferred>#awaitFirstWithDeferred` has been added to identify which of `Deferred`s was
|
||||||
|
normally completed
|
||||||
|
* New extensions `Iterable<Deferred<T>>#invokeOnFirst` and `Iterable<DeferredAction<*, O>>.invokeFirstOf` have been
|
||||||
|
added
|
||||||
|
|
||||||
|
## 0.4.18
|
||||||
|
|
||||||
|
* `Coroutines`:
|
||||||
|
* New extension `Iterable<Deferred>#awaitFirst` has been added
|
||||||
|
* `Serialization`
|
||||||
|
* `Base 64`
|
||||||
|
* New `Base64ByteArraySerializer` has been added
|
||||||
|
|
||||||
## 0.4.17
|
## 0.4.17
|
||||||
|
|
||||||
* `Common`
|
* `Common`
|
||||||
|
@@ -0,0 +1,37 @@
|
|||||||
|
package dev.inmo.micro_utils.coroutines
|
||||||
|
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import kotlin.coroutines.*
|
||||||
|
|
||||||
|
suspend fun <T> Iterable<Deferred<T>>.awaitFirstWithDeferred(
|
||||||
|
scope: CoroutineScope,
|
||||||
|
cancelOnResult: Boolean = true
|
||||||
|
): Pair<Deferred<T>, T> = suspendCoroutine<Pair<Deferred<T>, T>> { continuation ->
|
||||||
|
scope.launch(SupervisorJob()) {
|
||||||
|
val scope = this
|
||||||
|
forEach {
|
||||||
|
scope.launch {
|
||||||
|
continuation.resume(it to it.await())
|
||||||
|
scope.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.also {
|
||||||
|
if (cancelOnResult) {
|
||||||
|
forEach {
|
||||||
|
try {
|
||||||
|
it.cancel()
|
||||||
|
} catch (e: IllegalStateException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun <T> Iterable<Deferred<T>>.awaitFirst(
|
||||||
|
scope: CoroutineScope,
|
||||||
|
cancelOnResult: Boolean = true
|
||||||
|
): T = awaitFirstWithDeferred(scope, cancelOnResult).second
|
||||||
|
suspend fun <T> Iterable<Deferred<T>>.awaitFirst(
|
||||||
|
cancelOthers: Boolean = true
|
||||||
|
): T = awaitFirst(CoroutineScope(coroutineContext), cancelOthers)
|
@@ -0,0 +1,40 @@
|
|||||||
|
package dev.inmo.micro_utils.coroutines
|
||||||
|
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
|
||||||
|
class DeferredAction<T, O>(
|
||||||
|
val deferred: Deferred<T>,
|
||||||
|
val callback: suspend (T) -> O
|
||||||
|
) {
|
||||||
|
suspend operator fun invoke() = callback(deferred.await())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T, O> Deferred<T>.buildAction(callback: suspend (T) -> O) = DeferredAction(this, callback)
|
||||||
|
|
||||||
|
suspend fun <O> Iterable<DeferredAction<*, O>>.invokeFirstOf(
|
||||||
|
scope: CoroutineScope,
|
||||||
|
cancelOnResult: Boolean = true
|
||||||
|
): O {
|
||||||
|
return map { it.deferred }.awaitFirstWithDeferred(scope, cancelOnResult).let { result ->
|
||||||
|
first { it.deferred == result.first }.invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun <O> invokeFirstOf(
|
||||||
|
scope: CoroutineScope,
|
||||||
|
vararg variants: DeferredAction<*, O>,
|
||||||
|
cancelOnResult: Boolean = true
|
||||||
|
): O = variants.toList().invokeFirstOf(scope, cancelOnResult)
|
||||||
|
|
||||||
|
suspend fun <T, O> Iterable<Deferred<T>>.invokeOnFirst(
|
||||||
|
scope: CoroutineScope,
|
||||||
|
cancelOnResult: Boolean = true,
|
||||||
|
callback: suspend (T) -> O
|
||||||
|
): O = map { it.buildAction(callback) }.invokeFirstOf(scope, cancelOnResult)
|
||||||
|
|
||||||
|
suspend fun <T, O> invokeOnFirst(
|
||||||
|
scope: CoroutineScope,
|
||||||
|
vararg variants: Deferred<T>,
|
||||||
|
cancelOnResult: Boolean = true,
|
||||||
|
callback: suspend (T) -> O
|
||||||
|
): O = variants.toList().invokeOnFirst(scope, cancelOnResult, callback)
|
@@ -0,0 +1,34 @@
|
|||||||
|
package dev.inmo.micro_utils.coroutines
|
||||||
|
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import org.junit.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
class AwaitFirstTests {
|
||||||
|
private fun CoroutineScope.createTestDeferred(value: Int, wait: Long = 100000) = async(start = CoroutineStart.LAZY) { delay(wait); value }
|
||||||
|
@Test
|
||||||
|
fun testThatAwaitFirstIsWorkingCorrectly() {
|
||||||
|
val baseScope = CoroutineScope(Dispatchers.Default)
|
||||||
|
val resultDeferred = baseScope.createTestDeferred(-1, 0)
|
||||||
|
val deferreds = listOf(
|
||||||
|
baseScope.async { createTestDeferred(0) },
|
||||||
|
baseScope.async { createTestDeferred(1) },
|
||||||
|
baseScope.async { createTestDeferred(2) },
|
||||||
|
resultDeferred
|
||||||
|
)
|
||||||
|
val controlJob = baseScope.launch {
|
||||||
|
delay(1000000)
|
||||||
|
}
|
||||||
|
val result = baseScope.launchSynchronously {
|
||||||
|
val result = deferreds.awaitFirst(baseScope)
|
||||||
|
|
||||||
|
assertTrue(baseScope.isActive)
|
||||||
|
assertTrue(controlJob.isActive)
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
assertEquals(baseScope.launchSynchronously { resultDeferred.await() }, result)
|
||||||
|
assertTrue(deferreds.all { it == resultDeferred || it.isCancelled })
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,27 @@
|
|||||||
|
package dev.inmo.micro_utils.coroutines
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.coroutines.asDeferred
|
||||||
|
import dev.inmo.micro_utils.coroutines.launchSynchronously
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import kotlin.test.*
|
||||||
|
|
||||||
|
class DoWithFirstTests {
|
||||||
|
@Test
|
||||||
|
fun testHandleOneOf() {
|
||||||
|
val scope = CoroutineScope(Dispatchers.Default)
|
||||||
|
val happenedDeferreds = mutableListOf<Int>()
|
||||||
|
val deferredWhichMustHappen = (-1).asDeferred
|
||||||
|
scope.launchSynchronously {
|
||||||
|
scope.launch {
|
||||||
|
((0 until 100).map {
|
||||||
|
DeferredAction(
|
||||||
|
scope.async { delay(10000); it },
|
||||||
|
happenedDeferreds::add
|
||||||
|
)
|
||||||
|
} + DeferredAction(deferredWhichMustHappen, happenedDeferreds::add)).invokeFirstOf(scope)
|
||||||
|
}.join()
|
||||||
|
}
|
||||||
|
assertEquals(1, happenedDeferreds.size)
|
||||||
|
assertEquals(scope.launchSynchronously { deferredWhichMustHappen.await() }, happenedDeferreds.first())
|
||||||
|
}
|
||||||
|
}
|
@@ -40,5 +40,5 @@ dokka_version=1.4.20
|
|||||||
# Project data
|
# Project data
|
||||||
|
|
||||||
group=dev.inmo
|
group=dev.inmo
|
||||||
version=0.4.17
|
version=0.4.20
|
||||||
android_code_version=21
|
android_code_version=24
|
||||||
|
@@ -18,3 +18,4 @@ open class Base64Serializer<T>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
object Base64StringSerializer : Base64Serializer<String>({ it }, { it })
|
object Base64StringSerializer : Base64Serializer<String>({ it }, { it })
|
||||||
|
object Base64ByteArraySerializer : Base64Serializer<ByteArray>({ it.decodeToString() }, { it.encodeToByteArray() })
|
||||||
|
7
serialization/encapsulator/build.gradle
Normal file
7
serialization/encapsulator/build.gradle
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
plugins {
|
||||||
|
id "org.jetbrains.kotlin.multiplatform"
|
||||||
|
id "org.jetbrains.kotlin.plugin.serialization"
|
||||||
|
id "com.android.library"
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "$mppProjectWithSerializationPresetPath"
|
@@ -0,0 +1,23 @@
|
|||||||
|
package dev.inmo.micro_utils.serialization.encapsulator
|
||||||
|
|
||||||
|
import kotlinx.serialization.KSerializer
|
||||||
|
import kotlinx.serialization.encoding.Encoder
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
data class Encapsulator<T : Any>(
|
||||||
|
val klass: KClass<T>,
|
||||||
|
val serializer: KSerializer<T>
|
||||||
|
) {
|
||||||
|
fun <O> encapsulate(
|
||||||
|
value: Any,
|
||||||
|
callback: KSerializer<T>.(T) -> O
|
||||||
|
): O? = if (klass.isInstance(value)) {
|
||||||
|
callback(serializer, value as T)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T : Any> Encapsulator<T>.tryEncode(encoder: Encoder, value: Any) = encapsulate(value) {
|
||||||
|
encoder.encodeSerializableValue(this, it)
|
||||||
|
}
|
1
serialization/encapsulator/src/main/AndroidManifest.xml
Normal file
1
serialization/encapsulator/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<manifest package="dev.inmo.micro_utils.serialization.encapsulator"/>
|
@@ -22,6 +22,7 @@ String[] includes = [
|
|||||||
":android:alerts:common",
|
":android:alerts:common",
|
||||||
":android:alerts:recyclerview",
|
":android:alerts:recyclerview",
|
||||||
":serialization:base64",
|
":serialization:base64",
|
||||||
|
":serialization:encapsulator",
|
||||||
|
|
||||||
":dokka"
|
":dokka"
|
||||||
]
|
]
|
||||||
|
Reference in New Issue
Block a user