From 9997e61b67fcbbadb763d074fd25710b29ea7b01 Mon Sep 17 00:00:00 2001 From: Paul Young <84700+paulyoung@users.noreply.github.com> Date: Sat, 15 Jun 2024 08:51:03 -0700 Subject: [PATCH] Add example for updating state in serial message callback (#375) * Add example for updating state in serial message callback * Use take instead of manually setting to None --------- Co-authored-by: Alexander Koz <888526+boozook@users.noreply.github.com> --- api/system/Cargo.toml | 5 ++ api/system/examples/README.md | 2 + ...update-state-in-serial-message-callback.rs | 81 +++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 api/system/examples/update-state-in-serial-message-callback.rs diff --git a/api/system/Cargo.toml b/api/system/Cargo.toml index 66d5fe82..988600d5 100644 --- a/api/system/Cargo.toml +++ b/api/system/Cargo.toml @@ -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] diff --git a/api/system/examples/README.md b/api/system/examples/README.md index 0758d4a7..8fb74cd8 100644 --- a/api/system/examples/README.md +++ b/api/system/examples/README.md @@ -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`. diff --git a/api/system/examples/update-state-in-serial-message-callback.rs b/api/system/examples/update-state-in-serial-message-callback.rs new file mode 100644 index 00000000..4cf185ed --- /dev/null +++ b/api/system/examples/update-state-in-serial-message-callback.rs @@ -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, +} + +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, event: SystemEvent, _sim_key_code: u32) -> EventLoopCtrl { + pub static mut STATE: Option = 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!();