10 releases

0.3.0 May 30, 2023
0.2.0 Jul 1, 2022
0.1.8 Apr 28, 2022
0.1.7 Sep 28, 2021
0.1.4 Jul 28, 2021

#314 in Concurrency

Download history 24/week @ 2024-03-09 4/week @ 2024-03-16 12/week @ 2024-03-30

66 downloads per month
Used in percy-preview-app

MIT/Apache

14KB
112 lines

app-world Actions Status docs

A framework agnostic approach to managing frontend application state.

Overview

app-world is simple thread-safe state management library that is designed to be useful in cross-platform frontend applications that manage large amounts of application state.

With app-world you have a single World which holds your application State, as well your application's Resources.

Resources are used to interface with the outside world, such as to write to a local file storage or to make an API request.

The only way to mutate application state is by sending a Msg (ignoring UnsafeCell based interior mutability).

This means that all state mutation can be handled in a single place, which makes it easy to reason about the application's behavior and decreases the likelihood of code duplication.

Cross-Platform Applications

app-world does not have any platform dependent code, making it suitable for writing cross-platform application logic that can run on the web, mobile and desktop.

For example, app-world can be used to manage state in a Rust core application that gets run on iOS, Android and in web browsers.

Thread Safety

You cannot acquire a write guard on the World directly. The only way to write to a World is via AppWorld::msg.

Multiple threads can read from an AppWorld simultaneously, but only one AppWorld::msg will be processed at a time.

This means that you can safely use app-world in multi-threaded applications without worrying about deadlocks.

Games

Multiple threads can read from an AppWorld simultaneously, but only one AppWorld::msg will be processed at a time.

This makes app-world a poor fit for games that have hardcore performance requirements where you might want many threads to be able to manipulate the World simultaneously.

In those cases, consider using one of the many existing Entity Component System crates.

Example Usage

use app_world::AppWorldWrapper;

struct MyAppWorld {
    state: MyAppState,
    resources: MyAppResources,
}

struct MyAppState {
    count: u32
}

struct MyAppResources {
    api_client: Arc<dyn SomeApiClient>
}

enum Msg {
    IncrementCount(u8)
}

type MyAppStateWrapper = AppWorldWrapper<MyAppState>;

impl AppWorld for MyAppWorld {
    type Msg = Msg;

    fn msg(&mut self, message: Msg) {
        match msg {
            Msg::IncrementCount(increment) => {
                self.count += 1;
            }
        }
    }
}

fn main () {
    let world = AppWorldWrapper::new(MyAppWorld::new());
    let world_clone = world.clone();

    assert_eq!(world.read().count, 0);
    world.msg(Msg::IncrementCount);
    world_clone.msg(Msg::IncrementCount);
    assert_eq!(world.read().count, 2);
}

Inspiration

No runtime deps

Features