Crate aper[][src]

Expand description


GitHub Repo stars wokflow state

Cartoonized face of an ape.

Aper is a data structure library in which every data structure is a state machine, and every mutation is a first-class value that can be serialized and sent over the network, or stored for later.

What is a state machine?

For the purposes of Aper, a state machine is simply a struct or enum that implements StateMachine and has the following properties:

  • It defines a StateMachine::Transition type, through which every possible change to the state can be described. It is usually useful, though not required, that this be an enum type.
  • It defines a StateMachine::Conflict type, which describes a conflict which may occur when a transition is applied that is not valid at the time it is applied. For simple types where a conflict is impossible, you can use NeverConflict for this.
  • All state updates are deterministic: if you clone a StateMachine and a Transition, the result of applying the cloned transition to the cloned state must be identical to applying the original transition to the original state.

Here’s an example StateMachine implementing a counter:

use aper::{StateMachine, NeverConflict};
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, Clone, Debug, Default)]
struct Counter { value: i64 };

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
enum CounterTransition {

impl StateMachine for Counter {
    type Transition = CounterTransition;
    type Conflict = NeverConflict;

    fn apply(&mut self, event: CounterTransition) -> Result<(), NeverConflict> {
        match event {
            CounterTransition::Reset => { self.value = 0 }
            CounterTransition::Increment(amount) => { self.value += amount }
            CounterTransition::Decrement(amount) => { self.value -= amount }


Why not CRDT?

Conflict-free replicated data types are a really neat way of representing data that’s shared between peers. In order to avoid the need for a central “source of truth”, CRDTs require that update operations (i.e. state transitions) be commutative. This allows them to represent a bunch of common data structures, but doesn’t allow you to represent arbitrarily complex update logic. By relying on a central authority, a state-machine approach allows you to implement data structures with arbitrary update logic, such as atomic moves of a value between two data structures, or the rules of a board game.

Aper is rapidly evolving. Consider this a technology preview. See the list of issues outstanding for version 1.0


Implementations of data structures built on crate::StateMachine.


An unconstructable type, meant to serve as the Conflict type of a StateMachine for which a conflict can never arise.


This trait provides the methods that Aper needs to be able to interact with an object as a state machine.

Derive Macros

Automatic implementation of StateMachine for a record struct where every field is also a StateMachine.