-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* extract store implementation to abstract store * created store combiner * updated docs
- Loading branch information
1 parent
edcf153
commit 234da18
Showing
9 changed files
with
261 additions
and
78 deletions.
There are no files selected for viewing
13 changes: 13 additions & 0 deletions
13
core/src/commonMain/kotlin/dev.valvassori/fluks/Combiner.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package dev.valvassori.fluks | ||
|
||
import kotlinx.coroutines.ExperimentalCoroutinesApi | ||
|
||
@ExperimentalCoroutinesApi | ||
fun <S0 : Fluks.State, S1 : Fluks.State, SOUT : Fluks.State> combiner( | ||
block: (S0, S1) -> SOUT, | ||
): Combiner<S0, S1, SOUT> = Combiner { s0, s1 -> block(s0, s1) } | ||
|
||
@ExperimentalCoroutinesApi | ||
fun interface Combiner<S0 : Fluks.State, S1 : Fluks.State, SOUT : Fluks.State> { | ||
fun combine(state0: S0, state1: S1): SOUT | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
107 changes: 107 additions & 0 deletions
107
core/src/commonMain/kotlin/dev.valvassori/fluks/Store.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
package dev.valvassori.fluks | ||
|
||
import kotlinx.coroutines.Dispatchers | ||
import kotlinx.coroutines.ExperimentalCoroutinesApi | ||
import kotlinx.coroutines.channels.Channel | ||
import kotlinx.coroutines.flow.collect | ||
import kotlinx.coroutines.flow.combine | ||
import kotlinx.coroutines.flow.launchIn | ||
import kotlinx.coroutines.flow.onEach | ||
import kotlinx.coroutines.launch | ||
import kotlin.coroutines.CoroutineContext | ||
|
||
@ExperimentalCoroutinesApi | ||
fun <S : Fluks.State> store( | ||
initialValue: S, | ||
context: CoroutineContext = Dispatchers.Default, | ||
reducer: Reducer<S>, | ||
): Fluks.Store<S> = object : AbstractStore<S>(context) { | ||
override val initialValue: S | ||
get() = initialValue | ||
|
||
override fun reduce( | ||
currentState: S, | ||
action: Fluks.Action | ||
): S = reducer.reduce(currentState, action) | ||
} | ||
|
||
@ExperimentalCoroutinesApi | ||
abstract class AbstractStore<S : Fluks.State> constructor( | ||
baseContext: CoroutineContext = Dispatchers.Default, | ||
) : Fluks.Store<S>(baseContext) { | ||
|
||
private val _queue: Channel<Fluks.Action> by lazy { Channel(Channel.UNLIMITED) } | ||
private var _middlewares: ChainNode<S> = asChainNode() | ||
|
||
init { | ||
scope.launch { | ||
register() | ||
for (action in _queue) { | ||
state.value = _middlewares.execute( | ||
store = this@AbstractStore, | ||
action = action | ||
) | ||
} | ||
} | ||
} | ||
|
||
final override fun dispatch(action: Fluks.Action) { | ||
_queue.offer(action) | ||
} | ||
|
||
final override fun applyMiddleware(middleware: Middleware<S>) { | ||
applyMiddleware(listOf(middleware)) | ||
} | ||
|
||
final override fun applyMiddleware(middlewares: List<Middleware<S>>) { | ||
_middlewares = createChain(middlewares) | ||
} | ||
|
||
private fun register() { | ||
GlobalDispatcher.register(this) | ||
} | ||
} | ||
|
||
@ExperimentalCoroutinesApi | ||
fun <S0 : Fluks.State, S1 : Fluks.State, SOUT : Fluks.State> combineStores( | ||
initialValue: SOUT, | ||
store0: Fluks.Store<S0>, | ||
store1: Fluks.Store<S1>, | ||
baseContext: CoroutineContext = Dispatchers.Default, | ||
combiner: Combiner<S0, S1, SOUT> | ||
) = object : AbstractCombinedStore<S0, S1, SOUT>(store0, store1, baseContext) { | ||
override val initialValue: SOUT | ||
get() = initialValue | ||
|
||
override fun combine(state0: S0, state1: S1): SOUT = combiner.combine(state0, state1) | ||
} | ||
|
||
@ExperimentalCoroutinesApi | ||
abstract class AbstractCombinedStore<S0 : Fluks.State, S1 : Fluks.State, SOUT : Fluks.State> constructor( | ||
store0: Fluks.Store<S0>, | ||
store1: Fluks.Store<S1>, | ||
baseContext: CoroutineContext = Dispatchers.Default, | ||
) : Fluks.Store<SOUT>(baseContext), Combiner<S0, S1, SOUT> { | ||
|
||
init { | ||
store0.state | ||
.combine(store1.state) { s0, s1 -> combine(s0, s1) } | ||
.onEach { sout -> state.value = sout } | ||
.launchIn(scope) | ||
} | ||
|
||
@Deprecated("Combined stores just react to changes in the other stores") | ||
final override fun reduce(currentState: SOUT, action: Fluks.Action): SOUT = currentState | ||
|
||
@Deprecated("Combined stores just react to changes in the other stores") | ||
final override fun dispatch(action: Fluks.Action) { | ||
} | ||
|
||
@Deprecated("Combined stores just react to changes in the other stores") | ||
final override fun applyMiddleware(middleware: Middleware<SOUT>) { | ||
} | ||
|
||
@Deprecated("Combined stores just react to changes in the other stores") | ||
override fun applyMiddleware(middlewares: List<Middleware<SOUT>>) { | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
76 changes: 76 additions & 0 deletions
76
core/src/jvmTest/kotlin/dev/valvassori/fluks/AbstractCombinedStoreTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package dev.valvassori.fluks | ||
|
||
import dev.valvassori.fluks.ext.value | ||
import dev.valvassori.fluks.util.CoroutineTestRule | ||
import kotlinx.coroutines.Dispatchers | ||
import kotlinx.coroutines.ExperimentalCoroutinesApi | ||
import kotlinx.coroutines.test.runBlockingTest | ||
import org.junit.Rule | ||
import org.junit.Test | ||
import kotlin.test.assertEquals | ||
|
||
@ExperimentalCoroutinesApi | ||
class AbstractCombinedStoreTest { | ||
|
||
@get:Rule | ||
val coroutineTestRule = CoroutineTestRule() | ||
|
||
object Inc : Fluks.Action | ||
|
||
private data class State0(val count0: Int) : Fluks.State | ||
private data class State1(val count1: Int) : Fluks.State | ||
private data class StateOut(val multiplication: Int) : Fluks.State | ||
|
||
private val store0 by lazy { | ||
store( | ||
initialValue = State0(count0 = 1), | ||
context = Dispatchers.Main | ||
) { currentState, action -> | ||
when (action) { | ||
Inc -> currentState.copy(count0 = currentState.count0 + 1) | ||
else -> currentState | ||
} | ||
} | ||
} | ||
|
||
private val store1 by lazy { | ||
store( | ||
initialValue = State1(count1 = 1), | ||
context = Dispatchers.Main | ||
) { currentState, action -> | ||
when (action) { | ||
Inc -> currentState.copy(count1 = currentState.count1 + 1) | ||
else -> currentState | ||
} | ||
} | ||
} | ||
|
||
@Test | ||
fun combinedStores_shouldRespondCorrectly() = coroutineTestRule.runBlockingTest { | ||
val combinedStores = combineStores( | ||
initialValue = StateOut(multiplication = 1), | ||
store0 = store0, | ||
store1 = store1, | ||
baseContext = Dispatchers.Main | ||
) { s0, s1 -> StateOut(multiplication = s0.count0 * s1.count1) } | ||
|
||
// 1 - 1 | ||
assertEquals(1, combinedStores.value.multiplication) | ||
|
||
// 2 - 1 | ||
store0.dispatch(Inc) | ||
assertEquals(2, combinedStores.value.multiplication) | ||
|
||
// 2 - 2 | ||
store1.dispatch(Inc) | ||
assertEquals(4, combinedStores.value.multiplication) | ||
|
||
// 2 - 3 | ||
store1.dispatch(Inc) | ||
assertEquals(6, combinedStores.value.multiplication) | ||
|
||
// 3 - 3 | ||
store0.dispatch(Inc) | ||
assertEquals(9, combinedStores.value.multiplication) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.