Skip to content

Commit

Permalink
Add example for updating state in serial message callback (#375)
Browse files Browse the repository at this point in the history
* Add example for updating state in serial message callback

* Use take instead of manually setting to None

---------

Co-authored-by: Alexander Koz <[email protected]>
  • Loading branch information
paulyoung and boozook authored Jun 15, 2024
1 parent 5e24b36 commit 9997e61
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 0 deletions.
5 changes: 5 additions & 0 deletions api/system/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ required-features = ["sys/entry-point", "sys/lang-items"]
name = "set-serial-message-callback"
crate-type = ["dylib", "staticlib"]
path = "examples/set-serial-message-callback.rs"

[[example]]
name = "update-state-in-serial-message-callback"
crate-type = ["dylib", "staticlib"]
path = "examples/update-state-in-serial-message-callback.rs"
required-features = ["sys/entry-point", "sys/lang-items"]

[package.metadata.playdate]
Expand Down
2 changes: 2 additions & 0 deletions api/system/examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ cargo playdate run -p=playdate-system --example=handler-boxed --features=sys/lan
cargo playdate run -p=playdate-system --example=handler-pinned --features=sys/lang-items,sys/entry-point

cargo playdate run -p=playdate-system --example=set-serial-message-callback --features=sys/lang-items,sys/entry-point

cargo playdate run -p=playdate-system --example=update-state-in-serial-message-callback --features=sys/lang-items,sys/entry-point
```

More information how to use [cargo-playdate][] in help: `cargo playdate --help`.
Expand Down
81 changes: 81 additions & 0 deletions api/system/examples/update-state-in-serial-message-callback.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#![no_std]
extern crate alloc;

#[macro_use]
extern crate sys;
extern crate playdate_system as system;

use alloc::string::String;
use core::ptr::NonNull;

use sys::EventLoopCtrl;
use sys::ffi::*;
use system::System;
use system::event::SystemEventExt as _;
use system::prelude::*;

struct State {
initialized: bool,
latest_message: Option<String>,
}

impl State {
fn new() -> Self {
Self { initialized: false,
latest_message: None }
}

/// System event handler
fn event(&'static mut self, event: SystemEvent) -> EventLoopCtrl {
match event {
SystemEvent::Init => {
System::Default().set_serial_message_callback(Some(|msg| {
self.latest_message = Some(msg);
}));

// Verify that `set_serial_message_callback` doesn't prevent us from
// updating other parts of `State`
self.initialized = true;

println!("Game init complete");
},
_ => {},
}
EventLoopCtrl::Continue
}
}

impl Update for State {
fn update(&mut self) -> UpdateCtrl {
if let Some(latest_message) = self.latest_message.take() {
println!("Latest message: {:#?}", latest_message);
}
UpdateCtrl::Continue
}
}

/// Entry point
#[no_mangle]
pub fn event_handler(_api: NonNull<PlaydateAPI>, event: SystemEvent, _sim_key_code: u32) -> EventLoopCtrl {
pub static mut STATE: Option<State> = None;

if unsafe { STATE.is_none() } {
let state = State::new();
unsafe { STATE = Some(state) }
}

// We call `set_update_handler` here because it requires (mutably) borrowing
// all of `State`.
//
// If we were to do this inside of `event` it would prevent us from being able
// to (mutably) borrow any of `State`, which means we couldn't update any
// state inside of our `set_serial_message_callback` closure.
if event == SystemEvent::Init {
unsafe { STATE.as_mut().expect("impossible").set_update_handler() }
}

unsafe { STATE.as_mut().expect("impossible").event(event) }
}

// Needed for debug build
ll_symbols!();

0 comments on commit 9997e61

Please sign in to comment.