Pass an mutable instance method to a function - rust

I am teaching myself Rust by creating a toy SDL2 lib for myself.
I created something similar in Go and am trying to port my code across. So far, this is the problem I cannot overcome. I want my library to have callback to a function on the program state so I can have keyboard events sent from my library code to my client code.
The aim is for the keydown events from the SDL keyboard event pump should trigger the on_keydown function on the state object. If I remove the State struct and just use static functions then it works. Of course this prevents me from changing the state of the program based on keyboard actions.
I am trying to use external crates as little as possible.
The relevant parts of the library.
pub enum GameCommand {
Quit,
Continue,
}
pub struct Window {
keydown_event: fn(Event) -> GameCommand,
}
impl Window {
pub fn set_keydown_event(&mut self, f: fn(e: Event) -> GameCommand) {
self.keydown_event = f;
}
pub fn run(&mut self) -> Result<(), String> {
let mut event_pump = self.game.context.event_pump()?;
'running: loop {
// Handle events
for event in event_pump.poll_iter() {
let mut gc = GameCommand::Continue;
match event {
Event::Quit { .. } => break 'running,
Event::KeyDown { repeat: false, .. } => {
gc = (self.keydown_event)(event);
}
_ => {}
}
if let GameCommand::Quit = gc {
break 'running
}
}
}
Ok(())
}
}
Now the relevant part of the client bin.
struct State {
bgcolor: Color,
}
impl State {
fn on_keydown(&mut self, event: Event) -> GameCommand {
match event {
Event::KeyDown { keycode: Some(Keycode::R), .. } => {
self.bgcolor.r += 1;
GameCommand::Continue
},
Event::KeyDown { keycode: Some(Keycode::G), .. } => {
self.bgcolor.g += 1;
GameCommand::Continue
},
Event::KeyDown { keycode: Some(Keycode::B), .. } => {
self.bgcolor.b += 1;
GameCommand::Continue
},
Event::KeyDown { keycode: Some(Keycode::Escape), ..} => {
GameCommand::Quit
},
_ => GameCommand::Continue,
}
}
}
Now the main function.
fn main() -> Result<(), String> {
let mut state = State {
bgcolor: Color::RGB(0, 0, 0),
};
let mut window = Window::new();
window.set_keydown_event(state.on_keydown);
Ok(())
}
There is a far bit of code skipped to keep it shortish. The error I get with this code is.
{
"code": "E0615",
"message": "attempted to take value of method `on_keydown` on type `State`\n\nmethod, not a field\n\nhelp: use parentheses to call the method: `(_)`",
}
If I window.set_keydown_event(state.on_keydown); I get this error.
{
"code": "E0308",
"message": "mismatched types\n\nexpected fn pointer, found enum `sdlgame::GameCommand`\n\nnote: expected fn pointer `fn(sdl2::event::Event) -> sdlgame::GameCommand`\n found enum `sdlgame::GameCommand`",
}
I assume the problem is the difference in function signatures. In the set_keydown_event function it expects.
fn(Event) -> GameCommand
Which is why a plain function not associated with a struct works. For the instance method to mutate state it requires the signature.
fn on_keydown(&mut self, event: Event) -> GameCommand
Initially, I am trying to achieve this is a single threaded manner as I am trying to keep things simple for me to reason out. Multi-threading will come later.
Is this possible in Rust and what is the correct way of achieving this result?
Thanks in advance.

Basically, you need to use function traits as well as an explicit closure so the call is bound to the variable. So, you'd change your Window to use a function trait:
// F is now the function type
pub struct Window<F: FnMut(Event) -> GameCommand> {
keydown_event: F,
}
Then you'd change your impl to support that function trait:
// put generic in impl
impl<F: FnMut(Event) -> GameCommand> Window<F> {
// take F as the parameter type now
pub fn set_keydown_event(&mut self, f: F) {
self.keydown_event = f;
}
pub fn run(&mut self) -> Result<(), String> {
// this function should stay the same
}
}
Then, you'd pass an explicit closure to it:
fn main() -> Result<(), String> {
let mut state = State {
bgcolor: Color::RGB(0, 0, 0),
};
let mut window = Window::new();
// binds the on_keydown function to the state variable
window.set_keydown_event(|x| state.on_keydown(x));
Ok(())
}

Related

Async: how to keep using the same future in a loop with select (no_std environment)?

I have two async functions: get_message and get_event. I'd like to perform an action whenever a message arrives or an event comes and do that forever in an infinite loop.
The simplified setup looks like this:
use futures::{future::select, future::Either, pin_mut};
impl MsgReceiver {
async fn get_message(&mut self) -> Message { /* ... */ }
}
impl EventListener {
async fn get_event(&mut self) -> Event { /* ... */ }
}
async fn eternal_task(receiver: MsgReceiver, listener: EventListener) -> ! {
let get_msg_fut = receiver.get_message();
pin_mut!(get_msg_fut);
loop {
let get_event_fut = listener.get_event();
pin_mut!(get_event_fut);
match select(get_event_fut, get_msg_fut).await {
Either::Left((ev, r_get_msg_fut)) => {
/* react to the event */
// r_get_msg_fut is not done, how to reuse it in the next iteration?
}
Either::Right((msg, r_get_event_fut)) => {
/* react to the message */
// it's fine to drop get_event_fut here
// the following line causes a double-mut-borrow error on receiver,
// despite receiver isn't borrowed anymore (the old future is completed and dropped)
let new_future = receiver.get_message();
}
};
}
}
I have three major questions here:
When an event comes first, how to tell rust that I want to reuse the incomplete get_message future on the next loop iteration?
When a message comes first, how to construct a new future without a borrow error?
When (2) is solved, how to put the new future into the same pinned memory location and use it on the next loop iteration?
I had success using this, but could not get rid of the Box::pin
use futures::{future::select, future::Either, pin_mut};
use std::sync::Mutex;
#[derive(Debug)]
struct MsgReceiver;
#[derive(Debug)]
struct EventListener;
#[derive(Debug)]
struct Message;
#[derive(Debug)]
struct Event;
impl MsgReceiver {
async fn get_message(&mut self) -> Message {
Message
}
}
impl EventListener {
async fn get_event(&mut self) -> Event {
Event
}
}
async fn eternal_task(receiver: MsgReceiver, mut listener: EventListener) -> ! {
let receiver = Mutex::new(receiver);
let mut f = None;
loop {
let get_msg_fut = match f.take() {
None => {
let mut l = receiver.lock();
Box::pin(async move {
l.get_message().await
})
}
Some(f) => f,
};
let get_event_fut = listener.get_event();
pin_mut!(get_event_fut);
match select(get_event_fut, get_msg_fut).await {
Either::Left((ev, r_get_msg_fut)) => {
/* react to the event */
// store the future for next iteration
f = Some(r_get_msg_fut);
}
Either::Right((msg, r_get_event_fut)) => {
/* react to the message */
}
};
}
}
#[tokio::main]
async fn main() {
eternal_task(MsgReceiver, EventListener).await;
}
I think this is tricky to get right, even with unsafe which would probably be needed to accomplish this. Persisting and reusing the same variables isn't too hard, its actually #2 that's the hardest (at least with the current borrow checker).
I found a solution that totally circumvents the problem by using the async-stream crate to provide an intermediary:
async fn eternal_task(mut receiver: MsgReceiver, mut listener: EventListener) -> ! {
let combined = futures::stream::select(
stream! { loop { yield Either::Left(receiver.get_message().await); } },
stream! { loop { yield Either::Right(listener.get_event().await); } },
);
pin_mut!(combined);
while let Some(msg_or_evt) = combined.next().await {
match msg_or_evt {
Either::Left(msg) => {
// do something with msg
}
Either::Right(evt) => {
// do something with evt
}
};
}
unreachable!()
}
It uses the stream! macro to generate a type that continuously calls and yields values from .get_message() and .get_event(). It then uses futures::stream::select and Either to combine them. And then its just a matter of looping over the results. It works in #![no_std].

Cannot get wrapping of filter to compile

I have the goal of wrapping an Iterator<Item = rusb::Device<_> to Iterator<Item = LitraDevice>. The latter contains specific implementation.
To make this work I tried the following code:
use std::iter::Filter;
use rusb;
const VENDOR: u16 = 0x046d;
const PRODUCT: u16 = 0xc900;
struct LitraDevice {
dev: rusb::Device<rusb::GlobalContext>,
}
pub struct LitraDevices {
unfiltered: rusb::DeviceList<rusb::GlobalContext>,
}
struct LitraDeviceIterator<'a> {
it: Filter<rusb::Devices<'a, rusb::GlobalContext>, for<'r> fn(&'r rusb::Device<rusb::GlobalContext>) -> bool>,
}
impl LitraDevices {
pub fn new() -> Self {
let unfiltered = rusb::devices().unwrap();
LitraDevices { unfiltered }
}
fn can_not_handle<'r>(dev: &'r rusb::Device<rusb::GlobalContext>) -> bool {
let desc = dev.device_descriptor().unwrap();
match (desc.vendor_id(), desc.product_id()) {
(VENDOR, PRODUCT) => (),
_ => return true,
}
match desc.class_code() {
LIBUSB_CLASS_HID => return true, // Skip HID devices, they are handled directly by OS libraries
_ => return false,
}
}
pub fn iter<'a>(self) -> LitraDeviceIterator<'a> {
let it = self.unfiltered.iter().filter(Self::can_not_handle);
LitraDeviceIterator{
it,
}
}
}
impl <'a> Iterator for LitraDeviceIterator<'a> {
type Item = LitraDevice;
fn next(&mut self) -> Option<Self::Item> {
let n = self.it.next();
match n {
Some(Device) => return Some(LitraDevice{dev: n.unwrap()}),
None => return None,
}
}
}
Now I really cannot figure out how to code LitraDeviceIterator so that it wraps the filtered iterator.
All code iterations I have tried so far turn into a generic nightmare very quickly.
I rewrote your iter() to yield LitraDevice, you can surely take it wherever you wanted to go from there.
The first underlying issue is that filter() yields references, but in cases like these, you actually mean to move yielded items while filtering. That's what filter_map() is capable of. That way, you can scrap the references, greatly simplifying your code.
(This code does not work yet, read on)
pub fn iter(self) -> impl Iterator<Item = LitraDevice> {
self.unfiltered.iter().filter_map(|dev| {
(!Self::can_not_handle(&dev))
.then_some(dev)
.map(|dev| LitraDevice { dev })
})
}
Now, there's a second little issue at play her: rusb::DeviceList<T : UsbContext>>::iter(&self) returns rusb::Devices<'_, T>, '_ being the anonymous lifetime inferred from &self. Meaning, while you can drive rusb::Devices<'_, T> to yield Device<T>s, you can not actually keep it around longer than self.unfiltered. More specifically, as you consume self in iter(), you can not return an iterator referencing that rusb::Devices<'_, T> from iter(). One solution is to immediately collect, then again moving into an iterator.
pub fn iter(self) -> impl Iterator<Item = LitraDevice> {
let devices = self.unfiltered.iter().collect::<Vec<_>>();
devices.into_iter().filter_map(|dev| {
(!Self::can_not_handle(&dev))
.then_some(dev)
.map(|dev| LitraDevice { dev })
})
}

Is there a way to pass an extra value to the panic handler?

I'm writing a UEFI OS loader, and I use the system table provided by efi_main in the panic handler to print a string on the console. Currently, I'm using a global static variable and a helper function to access it like this:
static SYSTEM_TABLE_WRAPPER: Lazy<Spinlock<Option<SystemTable>>> =
Lazy::new(|| Spinlock::new(None));
#[panic_handler]
fn panic(i: &PanicInfo<'_>) -> ! {
// SAFETY: The existing lock is forgotten. There is no way to access the lock from the panic
// handler.
unsafe { unlock_system_table() }
error!("{}", i);
loop {
x86_64::instructions::hlt();
}
}
pub fn _print(args: fmt::Arguments<'_>) {
let mut st = crate::system_table();
let mut stdout = st.con_out();
let _ = stdout.write_fmt(args);
}
#[macro_export]
macro_rules! println {
() => {
$crate::print!("\n");
};
($($arg:tt)*)=>{
$crate::print!("{}\n",core::format_args!($($arg)*));
}
}
#[macro_export]
macro_rules! print {
($($arg:tt)*) => {
$crate::io::_print(core::format_args!($($arg)*));
};
}
pub(crate) fn system_table<'a>() -> MappedSpinlockGuard<'a, uefi_wrapper::SystemTable> {
let st = SYSTEM_TABLE_WRAPPER.try_lock();
let st = st.expect("Failed to lock the global System Table.");
SpinlockGuard::map(st, |st| {
let st = st.as_mut();
let st = st.expect("The global System Table is not initialized.");
&mut st.0
})
}
Although this works correctly, I'd like to avoid using any global variables if possible. Is there a way to do that?
I dont think so. If its possible, any parameter would be a global as well. Making it more complex.
Global variables are ok for this. Create your own global panic object and give it to a new panic handler from the real one.
Because there seems to be no way to do that, I changed the way.
Firstly, I defined the uefi_print and uefi_println macros.
#[macro_export]
macro_rules! uefi_print{
($st:expr,$($arg:tt)*)=>{
$crate::io::_print($st,format_args!($($arg)*));
}
}
#[macro_export]
macro_rules! uefi_println {
($st:expr) => {
$crate::uefi_print!($st,"\n");
};
($st:expr,$($arg:tt)*)=>{
$crate::uefi_print!($st,"{}\n",format_args!($($arg)*));
}
}
#[doc(hidden)]
pub fn _print(st: &mut crate::SystemTable, args: fmt::Arguments<'_>) {
let mut con_out = st.con_out();
let _ = con_out.write_fmt(args);
}
These macros are similar to print and println macros, but the first parameter is the mutable reference to SystemTable. The example macro invocation:
#[no_mangle]
pub extern "win64" fn efi_main(h: uefi_wrapper::Handle, mut st: bootx64::SystemTable) -> ! {
let resolution = gop::set_preferred_resolution(&mut st);
uefi_println!(&mut st, "GOP info: {:?}", resolution,);
// ...
}
Secondly, I defined the uefi_panic macro:
#[macro_export]
macro_rules! uefi_panic {
($st:expr) => {
$crate::uefi_panic!($st, "explicit panic");
};
($st:expr,$($t:tt)+)=>{
$crate::uefi_println!($st,"panicked at '{}', {}:{}:{}",core::format_args!($($t)+),file!(),line!(),column!());
panic!();
}
}
#[panic_handler]
fn panic(_: &PanicInfo<'_>) -> ! {
loop {
x86_64::instructions::hlt();
}
}
The first parameter of the macro is also the mutable reference to SystemTable.
Thirdly, I defined a wrapper type for SystemTable that defines the additional method expect_ok.
#[repr(transparent)]
#[derive(Debug)]
pub struct SystemTable(uefi_wrapper::SystemTable);
impl SystemTable {
// ...
/// # Panics
///
/// This method panics if `result` is [`Err`].
pub fn expect_ok<T, E: fmt::Debug>(&mut self, result: Result<T, E>, msg: &str) -> T {
match result {
Ok(val) => val,
Err(e) => {
uefi_panic!(self, "{}: {:?}", msg, e);
}
}
}
}
Now I prefer this way to the previous method. The exit boot services function can move the ownership of SystemTable and ImageHandle. This way prevents these types from being used after calling it. After all, I should not create a global static SystemTable since it won't be valid after exiting the boot services.

How to implement callback on typing in textbox with rust druid (not lens, but a method call)?

I want to call the following method with arguments, either by passing them or from a closure:
fn set_border(&mut self, arg: &str, is_left_border: bool) -> () {
let val = arg.parse::<f64>();
match val {
Ok(float) => { if is_left_border {self.left_border = Some(float)} else {self.right_border = Some(float)}},
Err(_) => {}
}
}
when text is entered to the textbox. I didn't find a way to use lens to access methods, but I'm quite new to rust and decided to ask for advice.
As far as I'm concerned if I can "track" changes of the field and do it that way it will also do.
Thanks in advance.
You can use a Controller to be called when the TextBox receives a call to its update method and then check whether the data has changed:
use druid::{
AppLauncher,
WidgetExt,
Widget,
Env,
UpdateCtx,
WindowDesc,
widget::TextBox,
widget::Controller
};
struct UpdateCallback();
impl Controller<String, TextBox<String>> for UpdateCallback {
fn update(&mut self,
child: &mut TextBox<String>,
ctx: &mut UpdateCtx<'_, '_>,
old_data: &String,
data: &String,
env: &Env
) {
if old_data != data {
// the data has changed, you can call your function here
println!("{}", data);
}
// also inform the child that the data has changed
child.update(ctx, old_data, data, env)
}
}
fn build_root_widget() -> impl Widget<String> {
TextBox::new().controller(UpdateCallback())
}
fn main() {
AppLauncher::with_window(WindowDesc::new(build_root_widget)).launch("Test".to_string()).unwrap();
}
The relevant part here is the Controller impl for UpdateCallback as well as the call to controller() inside the build_root_widget() function.

A pattern for finite (game) state machine in Rust with changing behavior?

I'm trying to write a turn-based game in Rust and I'm running up against a wall in the language (unless I'm not understanding something quite right – I'm new to the language). Basically, I'd like to change states in my game where each state has different behavior. For example I have something like:
struct Game {
state: [ Some GameState implementer ],
}
impl Game {
fn handle(&mut self, event: Event) {
let new_state = self.handle(event);
self.state = new_state;
}
}
struct ChooseAttackerPhase {
// ...
}
struct ResolveAttacks {
// ...
}
impl ResolveAttacks {
fn resolve(&self) {
// does some stuff
}
}
trait GameState {
fn handle(&self, event: Event) -> [ A New GateState implementer ]
}
impl GameState for ChooseAttackerPhase {
fn handle(&self, event: Event) -> [ A New GameState implementer ] {
// ...
}
}
impl GameState for ResolveAttacks {
fn handle(&self, event: Event) -> [ A New GameState implementer ] {
// ...
}
}
This was my original plan. I want handle to be a pure function that returns a new GameState instance. But as I understand it, this is not currently possible in Rust. So I tried using enums with tuples, each with their respective handler, that ended up being a dead end since I would have to match for every state.
Anyways, the code is not from my original project. Its just an example. My question is: is there a pattern for doing this in Rust that I'm missing? I'd like to be able to separate the logic for things I need to do in each state that are unique to each state and avoid writing lengthy pattern matching statements.
Let me know if I need to clarify my question a bit more.
A finite state machine (FSM) can be directly modeled using two enums, one representing all the states and another representing all the transitions:
#[derive(Debug)]
enum Event {
Coin,
Push,
}
#[derive(Debug)]
enum Turnstyle {
Locked,
Unlocked,
}
impl Turnstyle {
fn next(self, event: Event) -> Turnstyle {
use Event::*;
use Turnstyle::*;
match self {
Locked => {
match event {
Coin => Unlocked,
_ => self,
}
},
Unlocked => {
match event {
Push => Locked,
_ => self,
}
}
}
}
}
fn main() {
let t = Turnstyle::Locked;
let t = t.next(Event::Push);
println!("{:?}", t);
let t = t.next(Event::Coin);
println!("{:?}", t);
let t = t.next(Event::Coin);
println!("{:?}", t);
let t = t.next(Event::Push);
println!("{:?}", t);
}
The biggest downside is that one method ends up becoming very cluttered with all the state / transition pairs. You can sometimes neaten up the match a bit by matching on the pairs:
match (self, event) {
(Locked, Coin) => Unlocked,
(Unlocked, Push) => Locked,
(prev, _) => prev,
}
avoid writing lengthy pattern matching statements.
Each match arm can be a function that you call for every unique action you'd like to do. Above, Unlocked could be replaced with a function called unlocked that does whatever it needs to.
using enums [...] ended up being a dead end since I would have to match for every state.
Note that you can use the _ to match any pattern.
A downside to the enum is that it is not open for other people to add to it. Maybe you'd like to have an extensible system for your game where mods can add new concepts. In that case, you can use traits:
#[derive(Debug)]
enum Event {
Damage,
Healing,
Poison,
Esuna,
}
#[derive(Debug)]
struct Player {
state: Box<PlayerState>,
}
impl Player {
fn handle(&mut self, event: Event) {
let new_state = self.state.handle(event);
self.state = new_state;
}
}
trait PlayerState: std::fmt::Debug {
fn handle(&self, event: Event) -> Box<PlayerState>;
}
#[derive(Debug)]
struct Healthy;
#[derive(Debug)]
struct Poisoned;
impl PlayerState for Healthy {
fn handle(&self, event: Event) -> Box<PlayerState> {
match event {
Event::Poison => Box::new(Poisoned),
_ => Box::new(Healthy),
}
}
}
impl PlayerState for Poisoned {
fn handle(&self, event: Event) -> Box<PlayerState> {
match event {
Event::Esuna => Box::new(Healthy),
_ => Box::new(Poisoned),
}
}
}
fn main() {
let mut player = Player { state: Box::new(Healthy) };
println!("{:?}", player);
player.handle(Event::Damage);
println!("{:?}", player);
player.handle(Event::Healing);
println!("{:?}", player);
player.handle(Event::Poison);
println!("{:?}", player);
player.handle(Event::Esuna);
println!("{:?}", player);
}
Now, you can implement whatever states you'd like.
I want handle to be a pure function that returns a new GameState instance.
You cannot return a GameState instance because the compiler needs to know how much space each value requires. If you could return a struct that took up 4 bytes in one call or 8 bytes from another, the compiler wouldn't have any idea how much space the call you actually make needs.
The trade-off you have to make is to always return a newly allocated trait object. This allocation is required to give a homogenous size to every possible variant of PlayerState that might arise.
In the future, there might be support for saying that a function returns a trait (fn things() -> impl Iterator for example). This is basically hiding the fact that there is a value with a known size that the programmer doesn't / cannot write. If I understand correctly, it would not help in this case because the ambiguity of size would not be determinable at compile time.
In the extremely rare case that your states don't have any actual state, you could create a shared, immutable, global instance of each state:
trait PlayerState: std::fmt::Debug {
fn handle(&self, event: Event) -> &'static PlayerState;
}
static HEALTHY: Healthy = Healthy;
static POISONED: Poisoned = Poisoned;
impl PlayerState for Healthy {
fn handle(&self, event: Event) -> &'static PlayerState {
match event {
Event::Poison => &POISONED,
_ => &HEALTHY,
}
}
}
impl PlayerState for Poisoned {
fn handle(&self, event: Event) -> &'static PlayerState {
match event {
Event::Esuna => &HEALTHY,
_ => &POISONED,
}
}
}
This will avoid the overhead (whatever it may be) of the allocation. I wouldn't try this until you know there's no state and there's lots of time spent in the allocation.
I'm experimenting with encoding the FSM into the type model. This requires each state and each event to have it's type but I guess it's just bytes underneath and the explicit types allow me to break the transitions apart. Here's a playground with a tourniquet example.
We start with the simplest assumptions. Machine is represented by it's states and transitions. An event transits the machine in one step to a new state, consuming old state. This allows for the machine to be encoded in immutable state and event structs. States implement this generic Machine trait to add transitions:
pub trait Machine<TEvent> {
type State;
fn step(self, event: TEvent) -> Self::State;
}
That's all the framework for this pattern really. The rest is application and implementation. You cannot make a transition that is not defined and there's no unpredictable state. It looks very readable. For instance:
enum State {
Go(Open),
Wait(Locked),
}
struct Locked {
price: u8,
credit: u8,
}
struct Open {
price: u8,
credit: u8,
}
struct Coin {
value: u8,
}
impl Machine<Coin> for Locked {
type State = State;
fn step(self, coin: Coin) -> Self::State {
let credit = self.credit + coin.value;
if credit >= self.price {
println!("Thanks, you've got enough: {}", credit);
State::Go(Open {
credit: credit,
price: self.price,
})
} else {
println!("Thanks, {} is still missing", self.price - credit);
State::Wait(Locked {
credit: credit,
price: self.price,
})
}
}
}
And the client code is pretty semantic, too:
let locked = Locked {
price: 25,
credit: 0,
};
match locked.step(Coin { value: 5 }) {
State::Go(open) => {println!("Weeeeeeeeeeeeee!");},
State::Wait(locked) => {panic!("Oooops");},
}
I was much inspired by Andrew Hobben's Pretty State Machine Pattern.
There is a (synthetic) example of Music Player implementation via the State design pattern in Rust here: https://github.com/fadeevab/design-patterns-rust/tree/main/behavioral/state
The State design pattern is described in detail in The Rust Book: https://doc.rust-lang.org/book/ch17-03-oo-design-patterns.html
The State pattern actually does what you need: changing states [in the game] where each state has different behavior (read, "different implementation of the trait State").
You'd need to define trait State as follows:
pub trait State {
fn event1(self: Box<Self>, game: &mut Game) -> Box<dyn State>;
fn event2(self: Box<Self>, game: &mut Game) -> Box<dyn State>;
}
Then you define a behavior of the each state:
struct AttackState;
impl State for AttackState{
fn event1(self: Box<Self>, game: &mut Game) -> Box<dyn State> {
game.do_one_thing();
// Transition to another state: Attack -> Resolve
Box::new(ResolveState)
}
}
struct ResolveState;
impl State for ResolveState {
fn event1(self: Box<Self>, game: &mut Game) -> Box<dyn State> {
game.do_another_thing();
// No state transition
self
}
}
Each state implements different actions over the game object.

Resources