Cedux is a tool which enables developer to write clean C applications that don't require an operating system.
It works like this:
- Application state is stored in a global tree which is created by the
CEDUX_DEFINE_STORE()
macro. - Producers of data dispatch actions to the store via calls to
cedux_dispatch_x()
. - Reducers, which are registered during application initialization, receive dispatched actions and the current state tree and are responsible for updating the state as needed.
- Optional Subscribers, which are also registered during application initialization, receive the new state tree after reducers process any actions.
- In the
main
loop, calls tocedux_run_x()
check for dispatched actions and forward them to all registered reducers.
- Try to only modify the state tree from within reducers.
- Use a tagged-union for the action type (see main.c)
Take a look at main.c for a simple example usage.
To use Cedux you must first create a store. A store consists of just your state tree, a queue for holding dispatched actions and a list for holding registered reducers.
The following macro is used to create a store:
CEDUX_DEFINE_STORE(TREE_TYPE, ACTION_TYPE, STORE_NAME)
In this macro, TREE_TYPE
is the type (structure definition) that describes your state tree.
ACTION_TYPE
is the type that describes the actions that can be dispatched to the store.
STORE_NAME
is used as the suffix to the generated store instance name and the suffix for the generated methods described below. In the following documentation, x represents the store name.
For example, CEDUX_DEFINE_STORE(struct my_app_state, struct action, my_store)
would create a store which contains a state tree of type struct my_app_state
. Actions of type struct action
could be dispatched to the store. After the macro, a variable my_store
exists which is the store. The state tree is accessible via my_store.tree
;
To initialize the store call cedux_init_x()
. This sets up the internal list and queue and returns the store.
cedux_register_x_reducer(store, reducer)
where store
is a pointer to the store created by CEDUX_DEFINE_STORE
and reducer
is a function pointer to a reducer function. The reducer function must have a signature of void reducer(<tree type pointer>, action)
cedux_register_x_subscriber(store, subscriber, data)
where store
is a pointer to the store created by CEDUX_DEFINE_STORE
, subscriber
is the subscriber function, and data
is optional extra data to be passed with each call to the subscriber. The subscriber function must have a signature of void subscriber(<tree type pointer>, void *data)
. Cedux does not look at or modify data
at all, so you can use it for whatever extra information you need, or just set it to NULL
and ignore it.
Call the dispatch function to send an action to the store. This method pushes the action into the stores action queue to be handled later by the run function.
cedux_dispatch_x(store, action)
where store
is a pointer to the store and action
is a variable for ACTION_TYPE
.
Somewhere in the main loop of your application you need to call the Cedux run function. This function checks if any actions have been dispatched and if so, pops them out of the action queue and sends them to all registered reducers.
cedux_run_x(TStore * p_store)
As an example, CEDUX_DEFINE_STORE(struct my_app_state, struct my_action, my_store)
would generate the following:
struct my_store_handle; // The struct definition for the store handle
struct my_store_handle cedux_init_my_store(void); // store init function
void cedux_dispatch_my_store(struct my_store_handle* p_store, struct my_action_def action); // action dispatch function
bool cedux_run_my_store(struct my_store_handle* p_store); // run function
To use Cedux you'll need to copy the following files into your application.
- cedux.h
- queue.h (Used for the action queue)
- list.h (Used to hold the registered reducers)
For more information on the queue implementation see: https://spin.atomicobject.com/2017/03/08/message-queue-for-c/