mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2025-10-15 20:30:27 +00:00
Compare commits
18 Commits
Author | SHA1 | Date | |
---|---|---|---|
040dd517d8 | |||
ffc2d23be7 | |||
49b009e59b | |||
778b6a555b | |||
b3730998e9 | |||
837758aebe | |||
6ac4149aa1 | |||
278584ae6a | |||
126f9d5f41 | |||
ce15ff4e0a | |||
382b956beb | |||
36deab4909 | |||
550fc59d9d | |||
9100a57458 | |||
74d9bbccd9 | |||
75e602a349 | |||
e73644db10 | |||
148e6bdae7 |
21
.github/workflows/dokka_push.yml
vendored
Normal file
21
.github/workflows/dokka_push.yml
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
name: Publish KDocs
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
jobs:
|
||||||
|
publishing:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions/setup-java@v1
|
||||||
|
with:
|
||||||
|
java-version: 1.8
|
||||||
|
- name: Build
|
||||||
|
run: ./gradlew dokkaHtml
|
||||||
|
- name: Publish KDocs
|
||||||
|
uses: peaceiris/actions-gh-pages@v3
|
||||||
|
with:
|
||||||
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
publish_dir: ./dokka/build/dokka/html
|
||||||
|
publish_branch: kdocs
|
30
CHANGELOG.md
30
CHANGELOG.md
@@ -1,5 +1,35 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.4.35
|
||||||
|
|
||||||
|
* `Versions`:
|
||||||
|
* `Kotlin Exposed`: `0.30.1` -> `0.30.2`
|
||||||
|
* `Serialization`:
|
||||||
|
* `TypedSerializer`:
|
||||||
|
* Project has been inited
|
||||||
|
|
||||||
|
## 0.4.34
|
||||||
|
|
||||||
|
* `Versions`:
|
||||||
|
* `uuid`: `0.2.3` -> `0.2.4`
|
||||||
|
* `Repos`:
|
||||||
|
* `AbstractExposedCRUDRepo` now implements `StandardCRUDRepo`
|
||||||
|
* `AbstractMutableAndroidCRUDRepo` now implements `StandardCRUDRepo`
|
||||||
|
|
||||||
|
## 0.4.33
|
||||||
|
|
||||||
|
* `Versions`:
|
||||||
|
* `Ktor`: `1.5.2` -> `1.5.3`
|
||||||
|
* `Coroutines`
|
||||||
|
* Add `WeakJob` workaround:
|
||||||
|
* `CoroutineScope#weakLaunch`
|
||||||
|
* `CoroutineScope#weakAsync`
|
||||||
|
|
||||||
|
## 0.4.32
|
||||||
|
|
||||||
|
* `Versions`:
|
||||||
|
* `Kotlin Exposed`: `0.29.1` -> `0.30.1`
|
||||||
|
|
||||||
## 0.4.31
|
## 0.4.31
|
||||||
|
|
||||||
* `Versions`:
|
* `Versions`:
|
||||||
|
@@ -0,0 +1,31 @@
|
|||||||
|
package dev.inmo.micro_utils.coroutines
|
||||||
|
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
import kotlin.coroutines.EmptyCoroutineContext
|
||||||
|
|
||||||
|
private fun CoroutineScope.createWeakSubScope() = CoroutineScope(coroutineContext.minusKey(Job)).also { newScope ->
|
||||||
|
coroutineContext.job.invokeOnCompletion { newScope.cancel() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun CoroutineScope.weakLaunch(
|
||||||
|
context: CoroutineContext = EmptyCoroutineContext,
|
||||||
|
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||||
|
block: suspend CoroutineScope.() -> Unit
|
||||||
|
): Job {
|
||||||
|
val scope = createWeakSubScope()
|
||||||
|
val job = scope.launch(context, start, block)
|
||||||
|
job.invokeOnCompletion { scope.cancel() }
|
||||||
|
return job
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> CoroutineScope.weakAsync(
|
||||||
|
context: CoroutineContext = EmptyCoroutineContext,
|
||||||
|
start: CoroutineStart = CoroutineStart.DEFAULT,
|
||||||
|
block: suspend CoroutineScope.() -> T
|
||||||
|
): Deferred<T> {
|
||||||
|
val scope = createWeakSubScope()
|
||||||
|
val deferred = scope.async(context, start, block)
|
||||||
|
deferred.invokeOnCompletion { scope.cancel() }
|
||||||
|
return deferred
|
||||||
|
}
|
@@ -0,0 +1,40 @@
|
|||||||
|
package dev.inmo.micro_utils.coroutines
|
||||||
|
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class WeakJob {
|
||||||
|
@Test
|
||||||
|
fun `test that weak jobs works correctly`() {
|
||||||
|
val scope = CoroutineScope(Dispatchers.Default)
|
||||||
|
lateinit var weakLaunchJob: Job
|
||||||
|
lateinit var weakAsyncJob: Job
|
||||||
|
scope.launchSynchronously {
|
||||||
|
val completeDeferred = Job()
|
||||||
|
coroutineScope {
|
||||||
|
weakLaunchJob = weakLaunch {
|
||||||
|
while (isActive) {
|
||||||
|
delay(100L)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
weakAsyncJob = weakAsync {
|
||||||
|
while (isActive) {
|
||||||
|
delay(100L)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
coroutineContext.job.invokeOnCompletion {
|
||||||
|
scope.launch {
|
||||||
|
delay(1000L)
|
||||||
|
completeDeferred.complete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
launch { delay(1000L); cancel() }
|
||||||
|
}
|
||||||
|
completeDeferred.join()
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(!weakLaunchJob.isActive)
|
||||||
|
assert(!weakAsyncJob.isActive)
|
||||||
|
}
|
||||||
|
}
|
@@ -9,15 +9,15 @@ android.enableJetifier=true
|
|||||||
kotlin_version=1.4.32
|
kotlin_version=1.4.32
|
||||||
kotlin_coroutines_version=1.4.3
|
kotlin_coroutines_version=1.4.3
|
||||||
kotlin_serialisation_core_version=1.1.0
|
kotlin_serialisation_core_version=1.1.0
|
||||||
kotlin_exposed_version=0.29.1
|
kotlin_exposed_version=0.30.2
|
||||||
|
|
||||||
ktor_version=1.5.2
|
ktor_version=1.5.3
|
||||||
|
|
||||||
klockVersion=2.0.7
|
klockVersion=2.0.7
|
||||||
|
|
||||||
github_release_plugin_version=2.2.12
|
github_release_plugin_version=2.2.12
|
||||||
|
|
||||||
uuidVersion=0.2.3
|
uuidVersion=0.2.4
|
||||||
|
|
||||||
# ANDROID
|
# ANDROID
|
||||||
|
|
||||||
@@ -39,10 +39,10 @@ crypto_js_version=4.0.0
|
|||||||
|
|
||||||
# Dokka
|
# Dokka
|
||||||
|
|
||||||
dokka_version=1.4.20
|
dokka_version=1.4.30
|
||||||
|
|
||||||
# Project data
|
# Project data
|
||||||
|
|
||||||
group=dev.inmo
|
group=dev.inmo
|
||||||
version=0.4.31
|
version=0.4.35
|
||||||
android_code_version=35
|
android_code_version=39
|
||||||
|
@@ -8,7 +8,8 @@ import kotlinx.coroutines.flow.*
|
|||||||
abstract class AbstractMutableAndroidCRUDRepo<ObjectType, IdType, InputValueType>(
|
abstract class AbstractMutableAndroidCRUDRepo<ObjectType, IdType, InputValueType>(
|
||||||
helper: StandardSQLHelper
|
helper: StandardSQLHelper
|
||||||
) : WriteStandardCRUDRepo<ObjectType, IdType, InputValueType>,
|
) : WriteStandardCRUDRepo<ObjectType, IdType, InputValueType>,
|
||||||
AbstractAndroidCRUDRepo<ObjectType, IdType>(helper) {
|
AbstractAndroidCRUDRepo<ObjectType, IdType>(helper),
|
||||||
|
StandardCRUDRepo<ObjectType, IdType, InputValueType> {
|
||||||
protected val newObjectsChannel = MutableSharedFlow<ObjectType>(64)
|
protected val newObjectsChannel = MutableSharedFlow<ObjectType>(64)
|
||||||
protected val updateObjectsChannel = MutableSharedFlow<ObjectType>(64)
|
protected val updateObjectsChannel = MutableSharedFlow<ObjectType>(64)
|
||||||
protected val deleteObjectsIdsChannel = MutableSharedFlow<IdType>(64)
|
protected val deleteObjectsIdsChannel = MutableSharedFlow<IdType>(64)
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
package dev.inmo.micro_utils.repos.exposed
|
package dev.inmo.micro_utils.repos.exposed
|
||||||
|
|
||||||
|
import dev.inmo.micro_utils.repos.StandardCRUDRepo
|
||||||
|
|
||||||
abstract class AbstractExposedCRUDRepo<ObjectType, IdType, InputValueType>(
|
abstract class AbstractExposedCRUDRepo<ObjectType, IdType, InputValueType>(
|
||||||
flowsChannelsSize: Int = 0,
|
flowsChannelsSize: Int = 0,
|
||||||
tableName: String = ""
|
tableName: String = ""
|
||||||
@@ -8,4 +10,5 @@ abstract class AbstractExposedCRUDRepo<ObjectType, IdType, InputValueType>(
|
|||||||
flowsChannelsSize,
|
flowsChannelsSize,
|
||||||
tableName
|
tableName
|
||||||
),
|
),
|
||||||
ExposedCRUDRepo<ObjectType, IdType>
|
ExposedCRUDRepo<ObjectType, IdType>,
|
||||||
|
StandardCRUDRepo<ObjectType, IdType, InputValueType>
|
||||||
|
7
serialization/typed_serializer/build.gradle
Normal file
7
serialization/typed_serializer/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,74 @@
|
|||||||
|
package dev.inmo.micro_utils.serialization.typed_serializer
|
||||||
|
|
||||||
|
import kotlinx.serialization.*
|
||||||
|
import kotlinx.serialization.builtins.serializer
|
||||||
|
import kotlinx.serialization.descriptors.*
|
||||||
|
import kotlinx.serialization.encoding.*
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
open class TypedSerializer<T : Any>(
|
||||||
|
kClass: KClass<T>,
|
||||||
|
presetSerializers: Map<String, KSerializer<out T>> = emptyMap()
|
||||||
|
) : KSerializer<T> {
|
||||||
|
protected val serializers = presetSerializers.toMutableMap()
|
||||||
|
@InternalSerializationApi
|
||||||
|
override open val descriptor: SerialDescriptor = buildSerialDescriptor(
|
||||||
|
"TextSourceSerializer",
|
||||||
|
SerialKind.CONTEXTUAL
|
||||||
|
) {
|
||||||
|
element("type", String.serializer().descriptor)
|
||||||
|
element("value", ContextualSerializer(kClass).descriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
@InternalSerializationApi
|
||||||
|
override open fun deserialize(decoder: Decoder): T {
|
||||||
|
return decoder.decodeStructure(descriptor) {
|
||||||
|
var type: String? = null
|
||||||
|
lateinit var result: T
|
||||||
|
while (true) {
|
||||||
|
when (val index = decodeElementIndex(descriptor)) {
|
||||||
|
0 -> type = decodeStringElement(descriptor, 0)
|
||||||
|
1 -> {
|
||||||
|
require(type != null) { "Type is null, but it is expected that was inited already" }
|
||||||
|
result = decodeSerializableElement(
|
||||||
|
descriptor,
|
||||||
|
1,
|
||||||
|
serializers.getValue(type)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
CompositeDecoder.DECODE_DONE -> break
|
||||||
|
else -> error("Unexpected index: $index")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@InternalSerializationApi
|
||||||
|
protected open fun <O: T> CompositeEncoder.encode(value: O) {
|
||||||
|
encodeSerializableElement(descriptor, 1, value::class.serializer() as KSerializer<O>, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
@InternalSerializationApi
|
||||||
|
override open fun serialize(encoder: Encoder, value: T) {
|
||||||
|
encoder.encodeStructure(descriptor) {
|
||||||
|
val valueSerializer = value::class.serializer()
|
||||||
|
val type = serializers.keys.first { serializers[it] == valueSerializer }
|
||||||
|
encodeStringElement(descriptor, 0, type)
|
||||||
|
encode(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
open fun <O: T> include(type: String, serializer: KSerializer<O>) {
|
||||||
|
serializers[type] = serializer
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun exclude(type: String) {
|
||||||
|
serializers.remove(type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T : Any> TypedSerializer(
|
||||||
|
presetSerializers: Map<String, KSerializer<out T>> = emptyMap()
|
||||||
|
) = TypedSerializer(T::class, presetSerializers)
|
@@ -0,0 +1,40 @@
|
|||||||
|
package dev.inmo.micro_utils.serialization.typed_serializer
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.builtins.ListSerializer
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import kotlin.random.Random
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class TypedSerializerTests {
|
||||||
|
interface Example {
|
||||||
|
val number: Number
|
||||||
|
}
|
||||||
|
val serialFormat = Json { }
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class Example1(override val number: Long) : Example
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class Example2(override val number: Double) : Example
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testThatSerializerWorksCorrectly() {
|
||||||
|
val serializer = TypedSerializer(
|
||||||
|
mapOf(
|
||||||
|
"long" to Example1.serializer(),
|
||||||
|
"double" to Example2.serializer()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val value1 = Example1(Random.nextLong())
|
||||||
|
val value2 = Example2(Random.nextDouble())
|
||||||
|
|
||||||
|
val list = listOf(value1, value2)
|
||||||
|
val serialized = serialFormat.encodeToString(ListSerializer(serializer), list)
|
||||||
|
val deserialized = serialFormat.decodeFromString(ListSerializer(serializer), serialized)
|
||||||
|
|
||||||
|
assertEquals(list, deserialized)
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1 @@
|
|||||||
|
<manifest package="dev.inmo.micro_utils.serialization.typed_serializer"/>
|
@@ -26,6 +26,7 @@ String[] includes = [
|
|||||||
":android:alerts:recyclerview",
|
":android:alerts:recyclerview",
|
||||||
":serialization:base64",
|
":serialization:base64",
|
||||||
":serialization:encapsulator",
|
":serialization:encapsulator",
|
||||||
|
":serialization:typed_serializer",
|
||||||
|
|
||||||
":dokka"
|
":dokka"
|
||||||
]
|
]
|
||||||
|
Reference in New Issue
Block a user