# r3bl_redux
## Why R3BL?
R3BLTUIlibrary&suiteofappsfocusedondeveloperproductivity
We are working on building command line apps in Rust which have rich text user interfaces (TUI).
We want to lean into the terminal as a place of productivity, and build all kinds of awesome
apps for it.
1. 🔮 Instead of just building one app, we are building a library to enable any kind of rich TUI
development w/ a twist: taking concepts that work really well for the frontend mobile and web
development world and re-imagining them for TUI & Rust.
- Taking inspiration from things like [React](https://react.dev/),
[SolidJS](https://www.solidjs.com/),
[Elm](https://guide.elm-lang.org/architecture/),
[iced-rs](https://docs.rs/iced/latest/iced/), [Jetpack
Compose](https://developer.android.com/compose),
[JSX](https://ui.dev/imperative-vs-declarative-programming),
[CSS](https://www.w3.org/TR/CSS/#css), but making everything async (so they can
be run in parallel & concurrent via [Tokio](https://crates.io/crates/tokio)).
- Even the thread running the main event loop doesn't block since it is async.
- Using proc macros to create DSLs to implement something inspired by
[CSS](https://www.w3.org/TR/CSS/#css) &
[JSX](https://ui.dev/imperative-vs-declarative-programming).
2. 🌎 We are building apps to enhance developer productivity & workflows.
- The idea here is not to rebuild `tmux` in Rust (separate processes mux'd onto a
single terminal window). Rather it is to build a set of integrated "apps" (or
"tasks") that run in the same process that renders to one terminal window.
- Inside of this terminal window, we can implement things like "app" switching,
routing, tiling layout, stacking layout, etc. so that we can manage a lot of TUI
apps (which are tightly integrated) that are running in the same process, in the
same window. So you can imagine that all these "app"s have shared application
state. Each "app" may also have its own local application state.
- Here are some examples of the types of "app"s we plan to build (for which this
infrastructure acts as the open source engine):
1. Multi user text editors w/ syntax highlighting.
2. Integrations w/ github issues.
3. Integrations w/ calendar, email, contacts APIs.
All the crates in the `r3bl-open-core`
[repo](https://github.com/r3bl-org/r3bl-open-core/) provide lots of useful
functionality to help you build TUI (text user interface) apps, along w/ general
niceties & ergonomics that all Rustaceans 🦀 can enjoy 🎉.
## Table of contents
- [Introduction](#introduction)
- [Changelog](#changelog)
- [Learn how these crates are built, provide feedback](#learn-how-these-crates-are-built-provide-feedback)
- [Middlewares](#middlewares)
- [Subscribers](#subscribers)
- [Reducers](#reducers)
- [Summary](#summary)
- [Small example step by step](#small-example-step-by-step)
- [Complete example in one go](#complete-example-in-one-go)
## Introduction
`Store` is thread safe and asynchronous (using Tokio). You have to implement `async` traits in
order to use it, by defining your own reducer, subscriber, and middleware trait objects. You
also have to supply the Tokio runtime, this library will not create its own runtime. However,
for best results, it is best to use the multithreaded Tokio runtime.
Once you setup your Redux store w/ your reducer, subscriber, and middleware, you can use it by
calling `spawn_dispatch_action!( store, action )`. This kicks off a parallel Tokio task that
will run the middleware functions, reducer functions, and finally the subscriber functions. So
this will not block the thread of whatever code you call this from. The
`spawn_dispatch_action!()` macro itself is not `async`. So you can call it from non `async`
code, however you still have to provide a Tokio executor / runtime, without which you will get a
panic when `spawn_dispatch_action!()` is called.
> Here are some interesting links for you to look into further:
>
> 1. [In depth guide on this Redux
> implementation](https://developerlife.com/2022/03/12/rust-redux/).
> 2. [Code example of an address book using
> Redux](https://github.com/r3bl-org/address-book-with-redux-tui).
> 3. [Code example of TUI apps using
> Redux](https://github.com/r3bl-org/r3bl-open-core/tree/main/tui/examples/demo).
## Changelog
Please check out the
[changelog](https://github.com/r3bl-org/r3bl-open-core/blob/main/CHANGELOG.md#r3bl_redux)
to see how the library has evolved over time.
## Learn how these crates are built, provide feedback
To learn how we built this crate, please take a look at the following resources.
- If you like consuming video content, here's our [YT channel](https://www.youtube.com/@developerlifecom). Please consider [subscribing](https://www.youtube.com/channel/CHANNEL_ID?sub_confirmation=1).
- If you like consuming written content, here's our developer [site](https://developerlife.com/). Please consider subscribing to our [newsletter](https://developerlife.com/subscribe.html).
- If you have questions, please join our [discord server](https://discord.gg/8M2ePAevaM).
## Middlewares
Your middleware (`async` trait implementations) will be run concurrently or in parallel via
Tokio tasks. You get to choose which `async` trait to implement to do one or the other. And
regardless of which kind you implement the `Action` that is optionally returned will be
dispatched to the Redux store at the end of execution of all the middlewares (for that
particular `spawn_dispatch_action!()` call).
1. `AsyncMiddlewareSpawns` - Your middleware has to use `tokio::spawn` to run
`async` blocks in a [separate
thread](https://docs.rs/tokio/latest/tokio/task/index.html#spawning) and return a
`JoinHandle` that contains an `Option`. You can use [tokio::task::spawn] to
spawn parallel blocks of code in your `async` functions. These are added to the
store via a call to `add_middleware_spawns(...)`.
2. `AsyncMiddleware` - They are will all be run together concurrently using
[`futures::join_all()`](https://docs.rs/futures/latest/futures/future/fn.join_all.html).
These are added to the store via a call to `add_middleware(...)`.
## Subscribers
The subscribers will be run asynchronously via Tokio tasks. They are all run together
concurrently but not in parallel, using
[`futures::join_all()`](https://docs.rs/futures/latest/futures/future/fn.join_all.html).
## Reducers
The reducer functions are also are `async` functions that are run in the tokio runtime. They're
also run one after another in the order in which they're added.
âš¡ **Any functions or blocks that you write which uses the Redux library will have to be marked
`async` as well. And you will have to spawn the Tokio runtime by using the `#[tokio::main]`
macro. If you use the default runtime then Tokio will use multiple threads and its task stealing
implementation to give you parallel and concurrent behavior. You can also use the single
threaded runtime; its really up to you.**
1. To create middleware you have to implement the `AsyncMiddleware` trait or
`AsyncMiddlewareSpawns` trait. Please read the [`AsyncMiddleware`
docs](https://docs.rs/r3bl_rs_utils/latest/r3bl_rs_utils/redux/async_middleware/trait.AsyncMiddleware.html)
for examples of both. The `run()` method is passed two arguments: the `State` and the
`Action`.
1. For `AsyncMiddlewareSpawns` in your `run()` implementation you can use
[tokio::task::spawn] surround your code. And this will return a
`JoinHandle