Compare commits

..

22 Commits

Author SHA1 Message Date
18908a01d7 rewrite the way to use onStateHandlingErrorHandler inside of DefaultStatesMachine 2022-05-19 20:42:22 +06:00
b22fbfb3bc StateHandlingErrorHandler 2022-05-19 20:22:34 +06:00
57aaea88b6 Update gradle.properties 2022-05-17 12:38:15 +06:00
140949c5ea Update CHANGELOG.md 2022-05-17 12:32:59 +06:00
639241e0d3 Update libs.versions.toml 2022-05-17 12:31:50 +06:00
e0eb42bc2d update dexcount 2022-05-16 17:38:49 +06:00
7990b21cc5 add SharedPreferencesKeyValueRepo 2022-05-16 17:34:34 +06:00
2ba5c97709 start 0.10.5 2022-05-16 17:33:49 +06:00
33b7c85fc2 Merge pull request #154 from InsanusMokrassar/0.10.4
0.10.4
2022-05-12 17:24:13 +06:00
7f6c02ffdf update serialization 2022-05-12 17:04:53 +06:00
f368616e6f start 0.10.4 2022-05-12 17:03:59 +06:00
dd632f4203 Merge pull request #153 from InsanusMokrassar/0.10.3
0.10.3
2022-05-11 08:42:24 +06:00
a8f3ae501b Update CHANGELOG.md 2022-05-11 08:34:44 +06:00
ea76963ac2 Update libs.versions.toml 2022-05-11 08:33:55 +06:00
99dfa97958 Merge pull request #152 from InsanusMokrassar/0.10.3
0.10.3
2022-05-11 02:49:35 +06:00
f68270a5b3 fixes in AccumulatorFlow 2022-05-11 02:38:48 +06:00
542ed81034 start 0.10.3 2022-05-11 01:18:48 +06:00
404a11f5e7 Merge pull request #151 from InsanusMokrassar/0.10.2
0.10.2
2022-05-10 23:44:39 +06:00
411221070e Update CHANGELOG.md 2022-05-10 23:44:13 +06:00
25d35d0c76 Update compose 2022-05-10 15:03:04 +06:00
c72904d61c start 0.10.2 2022-05-10 15:00:56 +06:00
b94c9acd26 Merge pull request #150 from InsanusMokrassar/0.10.1
0.10.1
2022-04-29 23:20:27 +06:00
8 changed files with 97 additions and 29 deletions

View File

@@ -1,5 +1,32 @@
# Changelog
## 0.10.5
* `Versions`
* `Compose`: `1.2.0-alpha01-dev683` -> `1.2.0-alpha01-dev686`
* `Repos`
* `Android`:
* New function `SharedPreferencesKeyValueRepo`
* `FSM`
* Add `StateHandlingErrorHandler` and opportunity to handle states handling errors
## 0.10.4
* `Versions`:
* `Serialization`: `1.3.2` -> `1.3.3`
## 0.10.3
* `Versions`:
* `Compose`: `1.2.0-alpha01-dev682` -> `1.2.0-alpha01-dev683`
* `Coroutines`:
* Fixes in `AccumulatorFlow`
## 0.10.2
* `Versions`:
* `Compose`: `1.2.0-alpha01-dev675` -> `1.2.0-alpha01-dev682`
## 0.10.1
* `Versions`:

View File

@@ -6,11 +6,12 @@ import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlin.coroutines.cancellation.CancellationException
private sealed interface AccumulatorFlowStep
private data class DataRetrievedAccumulatorFlowStep(val data: Any) : AccumulatorFlowStep
private data class SubscribeAccumulatorFlowStep(val channel: Channel<Any>) : AccumulatorFlowStep
private data class UnsubscribeAccumulatorFlowStep(val channel: Channel<Any>) : AccumulatorFlowStep
private sealed interface AccumulatorFlowStep<T>
private data class DataRetrievedAccumulatorFlowStep<T>(val data: T) : AccumulatorFlowStep<T>
private data class SubscribeAccumulatorFlowStep<T>(val channel: Channel<T>) : AccumulatorFlowStep<T>
private data class UnsubscribeAccumulatorFlowStep<T>(val channel: Channel<T>) : AccumulatorFlowStep<T>
/**
* This [Flow] will have behaviour very similar to [SharedFlow], but there are several differences:
@@ -26,12 +27,12 @@ class AccumulatorFlow<T>(
private val subscope = scope.LinkedSupervisorScope()
private val activeData = ArrayDeque<T>()
private val dataMutex = Mutex()
private val channelsForBroadcast = mutableListOf<Channel<Any>>()
private val channelsForBroadcast = mutableListOf<Channel<T>>()
private val channelsMutex = Mutex()
private val steps = subscope.actor<AccumulatorFlowStep> { step ->
private val steps = subscope.actor<AccumulatorFlowStep<T>> { step ->
when (step) {
is DataRetrievedAccumulatorFlowStep -> {
if (activeData.first() === step.data) {
if (activeData.firstOrNull() === step.data) {
dataMutex.withLock {
activeData.removeFirst()
}
@@ -42,7 +43,7 @@ class AccumulatorFlow<T>(
dataMutex.withLock {
val dataToSend = activeData.toList()
safelyWithoutExceptions {
dataToSend.forEach { step.channel.send(it as Any) }
dataToSend.forEach { step.channel.send(it) }
}
}
}
@@ -58,24 +59,29 @@ class AccumulatorFlow<T>(
channelsMutex.withLock {
channelsForBroadcast.forEach { channel ->
safelyWithResult {
channel.send(it as Any)
channel.send(it)
}
}
}
}
override suspend fun collectSafely(collector: FlowCollector<T>) {
val channel = Channel<Any>(Channel.UNLIMITED, BufferOverflow.SUSPEND)
val channel = Channel<T>(Channel.UNLIMITED, BufferOverflow.SUSPEND)
steps.send(SubscribeAccumulatorFlowStep(channel))
for (data in channel) {
try {
collector.emit(data as T)
steps.send(DataRetrievedAccumulatorFlowStep(data))
} finally {
channel.cancel()
steps.send(UnsubscribeAccumulatorFlowStep(channel))
val result = runCatchingSafely {
for (data in channel) {
val emitResult = runCatchingSafely {
collector.emit(data)
}
if (emitResult.isSuccess || emitResult.exceptionOrNull() is CancellationException) {
steps.send(DataRetrievedAccumulatorFlowStep(data))
}
emitResult.getOrThrow()
}
}
channel.cancel()
steps.send(UnsubscribeAccumulatorFlowStep(channel))
result.getOrThrow()
}
}

View File

@@ -3,6 +3,8 @@ package dev.inmo.micro_utils.fsm.common
import dev.inmo.micro_utils.common.Optional
import dev.inmo.micro_utils.common.onPresented
import dev.inmo.micro_utils.coroutines.*
import dev.inmo.micro_utils.fsm.common.utils.StateHandlingErrorHandler
import dev.inmo.micro_utils.fsm.common.utils.defaultStateHandlingErrorHandler
import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
@@ -13,13 +15,24 @@ import kotlinx.coroutines.sync.withLock
* handling until [start] method will be called
*/
interface StatesMachine<T : State> : StatesHandler<T, T> {
suspend fun launchStateHandling(
state: T,
handlers: List<CheckableHandlerHolder<in T, T>>,
onStateHandlingErrorHandler: StateHandlingErrorHandler<T>
): T? {
return runCatchingSafely {
handlers.firstOrNull { it.checkHandleable(state) } ?.run {
handleState(state)
}
}.getOrElse {
onStateHandlingErrorHandler(state, it)
}
}
suspend fun launchStateHandling(
state: T,
handlers: List<CheckableHandlerHolder<in T, T>>
): T? {
return handlers.firstOrNull { it.checkHandleable(state) } ?.run {
handleState(state)
}
return launchStateHandling(state, handlers, defaultStateHandlingErrorHandler())
}
/**
@@ -38,8 +51,9 @@ interface StatesMachine<T : State> : StatesHandler<T, T> {
*/
operator fun <T: State> invoke(
statesManager: StatesManager<T>,
handlers: List<CheckableHandlerHolder<in T, T>>
) = DefaultStatesMachine(statesManager, handlers)
handlers: List<CheckableHandlerHolder<in T, T>>,
onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler()
) = DefaultStatesMachine(statesManager, handlers, onStateHandlingErrorHandler)
}
}
@@ -52,12 +66,17 @@ interface StatesMachine<T : State> : StatesHandler<T, T> {
open class DefaultStatesMachine <T: State>(
protected val statesManager: StatesManager<T>,
protected val handlers: List<CheckableHandlerHolder<in T, T>>,
protected val onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler()
) : StatesMachine<T> {
/**
* Will call [launchStateHandling] for state handling
*/
override suspend fun StatesMachine<in T>.handleState(state: T): T? = launchStateHandling(state, handlers)
override suspend fun launchStateHandling(state: T, handlers: List<CheckableHandlerHolder<in T, T>>): T? {
return launchStateHandling(state, handlers, onStateHandlingErrorHandler)
}
/**
* This
*/

View File

@@ -1,6 +1,8 @@
package dev.inmo.micro_utils.fsm.common
import dev.inmo.micro_utils.common.*
import dev.inmo.micro_utils.fsm.common.utils.StateHandlingErrorHandler
import dev.inmo.micro_utils.fsm.common.utils.defaultStateHandlingErrorHandler
import kotlinx.coroutines.*
import kotlinx.coroutines.sync.withLock
@@ -20,9 +22,11 @@ interface UpdatableStatesMachine<T : State> : StatesMachine<T> {
open class DefaultUpdatableStatesMachine<T : State>(
statesManager: StatesManager<T>,
handlers: List<CheckableHandlerHolder<in T, T>>,
onStateHandlingErrorHandler: StateHandlingErrorHandler<T> = defaultStateHandlingErrorHandler()
) : DefaultStatesMachine<T>(
statesManager,
handlers
handlers,
onStateHandlingErrorHandler
), UpdatableStatesMachine<T> {
protected val jobsStates = mutableMapOf<Job, T>()
@@ -34,7 +38,7 @@ open class DefaultUpdatableStatesMachine<T : State>(
*/
override suspend fun performStateUpdate(previousState: Optional<T>, actualState: T, scope: CoroutineScope) {
statesJobsMutex.withLock {
if (compare(previousState, actualState)) {
if (shouldReplaceJob(previousState, actualState)) {
statesJobs[actualState] ?.cancel()
}
val job = previousState.mapOnPresented {

View File

@@ -0,0 +1,6 @@
package dev.inmo.micro_utils.fsm.common.utils
typealias StateHandlingErrorHandler<T> = suspend (T, Throwable) -> T?
val DefaultStateHandlingErrorHandler: StateHandlingErrorHandler<*> = { _, _ -> null }
inline fun <T> defaultStateHandlingErrorHandler(): StateHandlingErrorHandler<T> = DefaultStateHandlingErrorHandler as StateHandlingErrorHandler<T>

View File

@@ -14,5 +14,5 @@ crypto_js_version=4.1.1
# Project data
group=dev.inmo
version=0.10.1
android_code_version=116
version=0.10.5
android_code_version=120

View File

@@ -1,10 +1,10 @@
[versions]
kt = "1.6.21"
kt-serialization = "1.3.2"
kt-serialization = "1.3.3"
kt-coroutines = "1.6.1"
jb-compose = "1.2.0-alpha01-dev675"
jb-compose = "1.2.0-alpha01-dev686"
jb-exposed = "0.38.2"
jb-dokka = "1.6.21"
@@ -16,7 +16,7 @@ ktor = "2.0.1"
gh-release = "2.3.7"
android-gradle = "7.0.4"
dexcount = "3.0.1"
dexcount = "3.1.0"
android-coreKtx = "1.7.0"
android-recyclerView = "1.2.1"

View File

@@ -160,3 +160,9 @@ class KeyValueStore<T : Any> internal constructor (
}
}
}
inline fun <T : Any> SharedPreferencesKeyValueRepo(
context: Context,
name: String = "default",
cacheValues: Boolean = false
) = context.keyValueStore<T>(name, cacheValues)