Expand description
§Solstack
Solstack is a library that enables the management of an application’s control flow through a state stack machine.
A Stack struct holds any number of States. When said Stack is ticked, it executes the main methods of the topmost State. This means that only the State at the top of the Stack is executed, while the ones below it are effectively paused. An exception are the State’s on_shadow_tick method introduced in v0.3.0 which is always executed independently of the State’s position on the Stack.
- You can read The Book.
- Take a look at the examples on the git repository.
- Search documentation at the crate’s docs.
- Watch the project develop through its changelog!
Project is in early development, things may change around! Take a look at the changelog before updating. Some text may imply that things are done, when they’re not, like The Book. There may be bugs, though the tests should guarantee there aren’t many.
§Overview
States have all of the methods you’ll need. Here’s an overview:
on_start— executed when thisStateis first pushed onto theStack.on_stop— executed when thisStateis popped from theStack.on_pause— executed when anotherStateis pushed on top of this one in theStack.on_resume— executed when this all of theStates above this one are popped from theStack.on_tick— executed every time theStackholding thisStatehas it’stickmethod called.on_shadow_tick— same ason_tick, but is always run independently of thisState’s position in theStack.
To hop between States you’ll return a Transition enum from on_tick or similar methods, requesting the Stack to perform such transition next tick. Here’s an overview:
Trans::None— requests theStackto do nothing.Trans::Quit— requests theStacktoPopeveryStateit is holding.Trans::Push(Box::new(State))— requests theStacktoPushthe providedStateon top.Trans::Pop— requests theStackto pop the topmostStateit is holding, deleting it.Trans::Replace(Box::new(State))— requests theStacktoPoponce andPushthe providedState.Trans::Isolate(Box::new(State))— requests theStacktoPopeverything andPushthe providedState.
Transitions may be requested directly of the
Stackor by returning aTransfrom inside aon_tickoron_shadow_tickmethod of aState.
§Features
-
An easy to implement
Statetrait. -
An easy to use State
StackMachinestruct. -
An easy to use set of
Transitions betweenStates. -
New in
v0.3.0:on_shadow_tickis provided onStates; similar toon_tickbut is always executed independently of theState’s position in theStack.
§Use case
Imagine you’re writing a game. You need a way of controlling the flow of your program. From the main menu to the game itself; from the game to the pause menu; or from the pause menu to quitting the program.
Solstack will help you structure these States and the Transitions between them.
Let’s model something. Here are our States (prefixed with S):
SMainMenu: where the player lands on initializing the game.SGame: where the actual gameplay logic resides.SPauseMenu: where the player can save, resume playing or exit.
Since the SMainMenu is the first thing the user will encounter, we’ll manually Push that State on our Stack when the program begins. Then we’ll tick the Stack in a main loop until there are no States inside it anymore.
You can manually perform transitions on a
Stackby using it’s methods on your local instance.The loop can be achieved by using the
Stack’sis_runningmethod.
The Stack, at the beginning of our program, will look like this:
SMainMenu
With only one sate on the Stack, it is on top; and so it will have it’s methods called. SMainMenu’s logic is simple: when the player presses START, it requests the Stack to Push an SGame. If that happens, the Stack would look like this:
SGameSMainMenu
Since only the topmost state is run by the stack’s tick, SMainMenu just sits there. Now the player is enjoying their game; but they wish to pause! Well, inside SGame all we have to do is request the stack to Push an SPauseMenu if the player ever presses ESC. Simple! Let’s see the Stack again:
SPauseMenuSGameSMainMenu
Now SPauseMenu is at the top. SGame will be paused; it’s still there, but it is not being executed. Inside the SPauseMenu there should be logic saying that if the player presses ESC again, the Stack should Pop. Popping means removing or completely deleting the topmost State at the Stack. In this case, SPauseMenu itself. The Stack would then, again, look like this:
SGameSMainMenu
Finally, SGame is at the top again! And so, it will resume exactly where it left off! If the player chooses to quit the game, you simply request the Stack to Quit, which will Pop every State it has, making the main loop end.
This concept can be extended to much bigger patterns; and hopefully you’ll find joy in structuring your application with solstack!
§Get started
This is just a very simplistic example in code. Take a look at the links at the start of this page, specially the examples on the project’s repository. The tests are also a good way of seeing how the library works internally.
use solstack::prelude::*;
use solstack::macros::*; // easy abstractions over boilerplate-y code.
// data available to `State`s for writing and reading
#[derive(Default)]
struct GameData {
value: i32
}
// a `State` that does what it says
struct AddOneAndPrintState;
impl State<GameData> for AddOneAndPrintState {
// run when this `State` is first pushed onto a `Stack`
fn on_start(&mut self, data: &mut GameData) {
data.value = 41;
println!("on_start `make data be 41` > GameData({})", data.value);
}
// run every time the `Stack` is ticked.
fn on_tick(&mut self, data: &mut GameData) -> Trans<GameData> {
data.value += 1;
println!("on_tick `add one to data` > GameData({})", data.value);
Trans::None
}
}
fn main() {
// initializing
let mut data = GameData::default();
let mut stack = Stack::<GameData>::new();
assert_eq!(data.value, 0);
// manually pushing and ticking the `Stack`
stack_push!(stack, data, AddOneAndPrintState);
assert_eq!(data.value, 41);
stack_tick!(stack, data);
assert_eq!(data.value, 42);
stack_tick!(stack, data);
assert_eq!(data.value, 43);
}§Thanks
The documentation will always be up to date.
Thank you for using solstack!
By Sol solmateusbraga@gmail.com
Modules§
Macros§
- stack_
isolate - Alternative to
stack.isolate(&mut data, Box::new(FooState {})). Usestack_isolate!(stack, data, FooState {}, BarState {}, ...)OBS.: Don’t use&mut dataas a parameter, but simplydata. - stack_
pop - Alternative to
stack.pop(&mut data). Usestack_pop!(stack, data)Orstack_pop!(stack, data, 3)3 being the amount of states to pop. OBS.: Don’t use&mut dataas a parameter, but simplydata. - stack_
push - Alternative to
stack.push(&mut data, Box::new(FooState {})). Usestack_push!(stack, data, FooState {}, BarState {}, ...) - stack_
quit - Alternative to
stack.quit(&mut data). Usestack_quit!(stack, data).OBS.: Don’t use&mut dataas a parameter, but simplydata. - stack_
replace - Alternative to
stack.replace(&mut data, Box::new(FooState {})). Usestack_replace!(stack, data, FooState {}, BarState {}, ...)OBS.: Don’t use&mut dataas a parameter, but simplydata. - stack_
tick - Alternative to
stack.tick(&mut data). Usestack_tick!(stack, data). OBS.: Don’t use&mut dataas a parameter, but simplydata. - trans_
isolate - Alternative to
Trans::Isolate(Box::new(FooState {})). Usetrans_isolate!(FooState {}) - trans_
none - Alternative to
Trans::None. Usetrans_none!() - trans_
pop - Alternative to
Trans::Pop. Usetrans_pop!() - trans_
push - Alternative to
Trans::Push(Box::new(FooState {})). Usetrans_push!(FooState {}) - trans_
quit - Alternative to
Trans::Quit. Usetrans_quit!() - trans_
replace - Alternative to
Trans::Replace(Box::new(FooState {})). Usetrans_replace!(FooState {})