Compare commits

...

11 Commits

Author SHA1 Message Date
14e666f18d create encpsulator 2021-01-21 10:10:52 +06:00
cce914091c start 0.4.20 2021-01-21 10:10:03 +06:00
d7cd3db8e2 Merge pull request #40 from InsanusMokrassar/0.4.19
0.4.19
2021-01-19 13:29:36 +06:00
0d8f844314 updates in coroutines 2021-01-19 13:28:50 +06:00
abd0cb2031 start 0.4.19 2021-01-19 13:24:38 +06:00
79ef03ed0c Merge pull request #39 from InsanusMokrassar/0.4.18
0.4.18
2021-01-17 17:17:39 +06:00
a3087cb650 awaitFirst 2021-01-17 17:15:54 +06:00
9acb9af338 Base64ByteArraySerializer 2021-01-17 16:53:24 +06:00
0c9283eb87 start 0.4.18 2021-01-17 16:49:10 +06:00
493d838201 Merge branch '0.4.17' 2021-01-14 21:22:42 +06:00
4f00eaa6d4 Merge pull request #37 from InsanusMokrassar/0.4.17
0.4.17
2021-01-14 20:55:45 +06:00
11 changed files with 195 additions and 2 deletions

View File

@@ -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`

View File

@@ -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)

View File

@@ -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)

View File

@@ -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 })
}
}

View File

@@ -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())
}
}

View File

@@ -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

View File

@@ -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() })

View File

@@ -0,0 +1,7 @@
plugins {
id "org.jetbrains.kotlin.multiplatform"
id "org.jetbrains.kotlin.plugin.serialization"
id "com.android.library"
}
apply from: "$mppProjectWithSerializationPresetPath"

View File

@@ -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)
}

View File

@@ -0,0 +1 @@
<manifest package="dev.inmo.micro_utils.serialization.encapsulator"/>

View File

@@ -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"
] ]