Skip to content

Introduce TypedStore<State,Action>! #125

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 29, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 40 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,25 @@
## Unreleased
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

---

## [Unreleased]

---

## [0.6.0]

### Added

- All missing ios, watchos, tvos and macos simulator targets added
- Added `androidNativeX64` and `androidNativeX86` targets
- Added proper android release and debug variants instead of piggybacking on jvm artefact
- New and improved `typedReducer` and `createTypedStore` builders for those needing a simple action-typed store.
Recommended to use with sealed interface hierarchies.

### Changed

@@ -16,50 +31,74 @@

- Remove deprecated `wasm32` target

---

## [0.5.5] - 2020-08-16

- update to Kotlin 1.4.0
- added platforms (androidNativeArm32, androidNativeArm64, iosArm32, linuxArm64, linuxX64,
mingwX86, tvosArm64, tvosX64, watchosArm32, watchosArm64, watchosX86)
- remove spek & atrium deps and use plain kotlin tests & assertions. Tests run for all platforms now.

---

## [0.5.2] - 2020-07-03

- publish all available platforms to maven
- add CI/CD through github actions

---

## [0.5.1] - 2020-06-11

- update lib dependency to api import, so core lib is included in redux-kotlin-threadsafe

---

## [0.5.0] - 2020-06-11

- kotlin 1.3.72
- createThreadSafeStore fun added for thread synchronized access
- createEnsureSameThreadStore to provide existing same-thread-enforcement

---

## [0.4.0] - 2020-03-23

- kotlin 1.3.70

---

## [0.3.2] - 2020-02-22

- issue #34 - incorrect same thread enforcement behavior fixed

---

## [0.3.1] - 2019-12-16

### Changed

- update same thread enforcement message to not be getState only

---

## [0.3.0] - 2019-12-16

### Added

- thread enforcement

---

## [0.2.9] - 2019-11-23

### Changed

- update Kotlin to 1.3.60

---

[Unreleased]: https://github.com/reduxkotlin/redux-kotlin/compare/v0.6.0...HEAD
[0.6.0]: https://github.com/reduxkotlin/redux-kotlin/compare/v0.5.5...0.6.0
[0.5.5]: https://github.com/reduxkotlin/redux-kotlin/releases/tag/v0.5.5
70 changes: 46 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@
![badge][badge-linux]
![badge][badge-windows]
![badge][badge-mac]
[![Slack chat](https://img.shields.io/badge/kotlinlang-%23redux-green?logo=slack&style=flat-square)](https://kotlinlang.slack.com/archives/C8A8G5F9Q)
[![Slack chat](https://img.shields.io/badge/kotlinlang-%23redux-green?logo=slack&style=flat-square)][slack]
[![Dokka docs](https://img.shields.io/badge/docs-dokka-orange?style=flat-square&logo=kotlin)](http://reduxkotlin.github.io/redux-kotlin)
[![Version maven-central](https://img.shields.io/maven-central/v/org.reduxkotlin/redux-kotlin?logo=apache-maven&style=flat-square)](https://mvnrepository.com/artifact/org.reduxkotlin/redux-kotlin/latest)
[![Version maven-snapshot](https://img.shields.io/maven-metadata/v?metadataUrl=https%3A%2F%2Foss.sonatype.org%2Fcontent%2Frepositories%2Fsnapshots%2Forg%2Freduxkotlin%2Fredux-kotlin%2Fmaven-metadata.xml&logo=apache-maven&label=maven-snapshot&style=flat-square)](https://oss.sonatype.org/content/repositories/snapshots/org/reduxkotlin/redux-kotlin/)
@@ -18,23 +18,29 @@ A redux standard for Kotlin that supports multiplatform projects.

Full documentation at http://reduxkotlin.org.

## Misson Statement
## Mission Statement

Provide a standard redux implementation for Kotlin. In doing so will foster a ecosystem of middleware, store
Provide a standard redux implementation for Kotlin. In doing so will foster a ecosystem of
middleware, store
enhancers, & dev tools. These core values will guide descisions for the project:

* core redux-kotlin will be a minimal implementation that other libraries can build upon
* modular development (follow example of https://github.com/reduxjs)
* support for all platforms supported by Kotlin multiplatform (JVM, iOS, Native, JS, WASM)
* developed in open and enable discussion for all interested parties via open channels (slack, github, etc. TBD)
* developed in open and enable discussion for all interested parties via open channels (slack,
github, etc. TBD)
* not owned by a individual or company

Redux in Kotlin, and in mobile in particular, may differ a bit from javascript. Many have found the basic pattern useful
on Android & iOS leading to tens of opensource redux libraries in Kotlin, Java, and Swift, yet an ecosystem has yet to
emerge. A port of javascript redux is a good starting point for creating a standard and will aid in cross-pollination of
Redux in Kotlin, and in mobile in particular, may differ a bit from javascript. Many have found the
basic pattern useful
on Android & iOS leading to tens of opensource redux libraries in Kotlin, Java, and Swift, yet an
ecosystem has yet to
emerge. A port of javascript redux is a good starting point for creating a standard and will aid in
cross-pollination of
middleware, store enhancers, & dev tools from the javascript world.

Redux has proven helpful for state management in mobile. A multiplatform Kotlin implementation & ecosystem will increase
Redux has proven helpful for state management in mobile. A multiplatform Kotlin implementation &
ecosystem will increase
developer productivity and code reuse across platforms.

[Droidcon NYC Slides](https://www.slideshare.net/PatrickJackson14/reduxkotlinorg-droidcon-nyc-2019)
@@ -44,31 +50,35 @@ Video TBA

__How to add to project:__

Artifacts are hosted on maven central. They are published with gradle metadata, so you may need to enable
with `enableFeaturePreview("GRADLE_METADATA")` in your settings.gradle file. For multiplatform, add the following to
Artifacts are hosted on maven central. They are published with gradle metadata, so you may need to
enable
with `enableFeaturePreview("GRADLE_METADATA")` in your settings.gradle file. For multiplatform, add
the following to
your shared module:

```kotlin
kotlin {
sourceSets {
commonMain { // <--- name may vary on your project
dependencies {
implementation("org.reduxkotlin:redux-kotlin-threadsafe:0.5.5")
implementation("org.reduxkotlin:redux-kotlin-threadsafe:_")
}
}
}
}
```

For JVM only:

```kotlin
implementation("org.reduxkotlin:redux-kotlin-threadsafe-jvm:0.5.5")
implementation("org.reduxkotlin:redux-kotlin-threadsafe-jvm:_>")
```

*Non threadsafe store is available. Typical usage will be with the threadsafe
store. [More info read here](https://www.reduxkotlin.org/introduction/getting-started)

Usage is very similar to JS Redux and those docs will be useful https://redux.js.org/. These docs are not an intro to
Usage is very similar to JS Redux and those docs will be useful https://redux.js.org/. These docs
are not an intro to
Redux, and just documentation on Kotlin specific bits. For more info on Redux in general, check
out https://redux.js.org/.

@@ -136,11 +146,13 @@ You then will have access to dispatch and subscribe functions from the `store`.
__Create a synchronized store__

```kotlin
val store = createThreadSafeStore(reducer, AppState(user, listOf()), applyMiddleware(loggingMiddleware))
val store =
createThreadSafeStore(reducer, AppState(user, listOf()), applyMiddleware(loggingMiddleware))
```

Access to `store` methods like `dispatch` and `getState` will be synchronized. Note: if using a thread safe store with
enhancers or middleware that require access to store methods, see usage below.
Access to `store` methods like `dispatch` and `getState` will be synchronized. Note: if using a
thread safe store with enhancers or middleware that require access to store methods, see usage
below.

__Create a synchronized store using an enhancer__

@@ -155,19 +167,27 @@ val store = createStore(
)
```

Access to `store` methods like `dispatch` and `getState` will be synchronized, and enhancers (eg. `applyMiddleware`)
that are placed above `createSynchronizedStoreEnhancer` in the enhancer composition chain will receive the synchronized
store.
Access to `store` methods like `dispatch` and `getState` will be synchronized, and enhancers (
eg. `applyMiddleware`) that are placed above `createSynchronizedStoreEnhancer` in the enhancer
composition chain will receive the synchronized store.

## Communication
## Extensions

Want to give feedback, contribute, or ask questions?
Here's a list of optional extensions available. Raise an issue to add yours!

__\#redux__ slack channel in [kotlinlang](https://kotlinlang.slack.com)
- [redux-kotlin-thunk](https://github.com/reduxkotlin/redux-kotlin-thunk)
- [redux-kotlin-compose](https://github.com/reduxkotlin/redux-kotlin-compose)
- [presenter-middleware](https://github.com/reduxkotlin/presenter-middleware)

Trello boards - https://trello.com/reduxkotlinorg
## Communication

Or create an issue on [github](https://github.com/reduxkotlin/redux-kotlin/issues).
Want to give feedback, contribute, or ask questions?

- Chat on [#redux][slack] slack channel
- Use [Trello boards](https://trello.com/reduxkotlinorg)
- Raise GitHub [issues](https://github.com/reduxkotlin/redux-kotlin/issues)
- Ask questions on
GitHub [discussions](https://github.com/reduxkotlin/redux-kotlin/discussions/categories/q-a)

[badge-android]: http://img.shields.io/badge/platform-android-brightgreen.svg?style=flat

@@ -184,3 +204,5 @@ Or create an issue on [github](https://github.com/reduxkotlin/redux-kotlin/issue
[badge-windows]: http://img.shields.io/badge/platform-windows-informational.svg?style=flat

[badge-mac]: http://img.shields.io/badge/platform-macos-lightgrey.svg?style=flat

[slack]: https://kotlinlang.slack.com/archives/C8A8G5F9Q
15 changes: 10 additions & 5 deletions gradle/detekt.yml
Original file line number Diff line number Diff line change
@@ -12,20 +12,25 @@ comments:
active: false
DeprecatedBlockTag:
active: true
excludes: [ "**/*Test.kt", "**/examples/**", "**/build-conventions/**" ]
excludes: [ "**/src/*Test/**", "**/examples/**", "**/build-conventions/**" ]
ignoreAnnotated: [ kotlin.Deprecated ]
OutdatedDocumentation:
active: true
excludes: [ "**/*Test.kt", "**/examples/**", "**/build-conventions/**" ]
excludes: [ "**/src/*Test/**", "**/examples/**", "**/build-conventions/**" ]
ignoreAnnotated: [ kotlin.Deprecated ]
allowParamOnConstructorProperties: false
UndocumentedPublicClass:
active: true
excludes: [ "**/*Test.kt", "**/examples/**", "**/build-conventions/**" ]
excludes: [ "**/src/*Test/**", "**/examples/**", "**/build-conventions/**" ]
ignoreAnnotated: [ kotlin.Deprecated ]
UndocumentedPublicFunction:
active: true
excludes: [ "**/*Test.kt", "**/examples/**", "**/build-conventions/**" ]
excludes: [ "**/src/*Test/**", "**/examples/**", "**/build-conventions/**" ]
ignoreAnnotated: [ kotlin.Deprecated ]
UndocumentedPublicProperty:
active: true
excludes: [ "**/*Test.kt", "**/examples/**", "**/build-conventions/**" ]
ignoreAnnotated: [ kotlin.Deprecated ]
excludes: [ "**/src/*Test/**", "**/examples/**", "**/build-conventions/**" ]

naming:
InvalidPackageDeclaration:
Original file line number Diff line number Diff line change
@@ -3,7 +3,11 @@ package org.reduxkotlin.threadsafe
import org.reduxkotlin.Reducer
import org.reduxkotlin.Store
import org.reduxkotlin.StoreEnhancer
import org.reduxkotlin.TypedReducer
import org.reduxkotlin.TypedStore
import org.reduxkotlin.asTyped
import org.reduxkotlin.createStore
import org.reduxkotlin.typedReducer

/**
* Creates a SYNCHRONIZED, THREADSAFE Redux store that holds the state tree.
@@ -32,4 +36,20 @@ public fun <State> createThreadSafeStore(
reducer: Reducer<State>,
preloadedState: State,
enhancer: StoreEnhancer<State>? = null
): Store<State> = SynchronizedStore(createStore(reducer, preloadedState, enhancer))
): Store<State> = ThreadSafeStore(createStore(reducer, preloadedState, enhancer))

/**
* Creates a thread-safe [TypedStore]. For further details see the matching [createThreadSafeStore].
*/
public inline fun <State, reified Action : Any> createTypedThreadSafeStore(
crossinline reducer: TypedReducer<State, Action>,
preloadedState: State,
noinline enhancer: StoreEnhancer<State>? = null
): TypedStore<State, Action> =
createThreadSafeStore(typedReducer(reducer), preloadedState, enhancer).asTyped()

/**
* Converts a given [Store] to a [ThreadSafeStore].
*/
public inline fun <State> Store<State>.asThreadSafe(): ThreadSafeStore<State> =
ThreadSafeStore(store)
Original file line number Diff line number Diff line change
@@ -13,12 +13,22 @@ import org.reduxkotlin.StoreEnhancer

* @returns {StoreEnhancer} A store enhancer that synchronizes the store.
*/
public fun <State> createSynchronizedStoreEnhancer(): StoreEnhancer<State> {
public fun <State> createThreadSafeStoreEnhancer(): StoreEnhancer<State> {
return { storeCreator ->
{ reducer, initialState, en: Any? ->
val store = storeCreator(reducer, initialState, en)
val synchronizedStore = SynchronizedStore(store)
val synchronizedStore = ThreadSafeStore(store)
synchronizedStore
}
}
}

@Deprecated(
"Renamed to createThreadSafeStoreEnhancer",
replaceWith = ReplaceWith(
expression = "createThreadSafeStoreEnhancer",
"org.reduxkotlin.threadsafe.createThreadSafeStoreEnhancer"
)
)
public fun <State> createSynchronizedStoreEnhancer(): StoreEnhancer<State> =
createThreadSafeStoreEnhancer()
Original file line number Diff line number Diff line change
@@ -2,7 +2,12 @@ package org.reduxkotlin.threadsafe

import kotlinx.atomicfu.locks.SynchronizedObject
import kotlinx.atomicfu.locks.synchronized
import org.reduxkotlin.*
import org.reduxkotlin.Dispatcher
import org.reduxkotlin.GetState
import org.reduxkotlin.Reducer
import org.reduxkotlin.Store
import org.reduxkotlin.StoreSubscriber
import org.reduxkotlin.StoreSubscription

/**
* Threadsafe wrapper for ReduxKotlin store that synchronizes access to each function using
@@ -11,21 +16,31 @@ import org.reduxkotlin.*
* This does have a performance impact for JVM/Native.
* TODO more info at [https://ReduxKotlin.org]
*/
public class SynchronizedStore<TState>(private val store: Store<TState>) : Store<TState>, SynchronizedObject() {

public class ThreadSafeStore<State>(override val store: Store<State>) :
Store<State>,
SynchronizedObject() {
override var dispatch: Dispatcher = { action ->
synchronized(this) { store.dispatch(action) }
}

override val getState: GetState<TState> = {
override val getState: GetState<State> = {
synchronized(this) { store.getState() }
}

override val replaceReducer: (Reducer<TState>) -> Unit = { reducer ->
override val replaceReducer: (Reducer<State>) -> Unit = { reducer ->
synchronized(this) { store.replaceReducer(reducer) }
}

override val subscribe: (StoreSubscriber) -> StoreSubscription = { storeSubscriber ->
synchronized(this) { store.subscribe(storeSubscriber) }
}
}

@Deprecated(
"Renamed to ThreadSafeStore",
replaceWith = ReplaceWith(
expression = "ThreadSafeStore",
"org.reduxkotlin.threadsafe.ThreadSafeStore"
)
)
public typealias SynchronizedStore<State> = ThreadSafeStore<State>
Loading