diff options
| author | Jomar Milan <jomarm@jomarm.com> | 2026-06-21 22:07:14 -0700 |
|---|---|---|
| committer | Jomar Milan <jomarm@jomarm.com> | 2026-06-21 22:26:33 -0700 |
| commit | 9c50777d53cacb96b211d1afb54f801a88dc07f5 (patch) | |
| tree | 9a1bf92ed22e6937e5a856d4620bf3704bcdb0fb /src/app.rs | |
| parent | 617a0b8338e61b1a3625f0cc7fa4f543cb23d701 (diff) | |
Privatize access to internal session map
This way, RwLockReadGuard isn't being juggled anywhere, and the bounds of the session MutexGuard is limited to the FnOnce explicitly passed to with_session (less room for accidents, nice!)
This approach was inspired by the source code of RegionMap of Bamboo (https://gitlab.com/macmv/bamboo ref 8e32b54a5e7a69986339fea465d4afcc20425dd7), which uses a similar RwLock<HashMap<_, Mutex<_>>>. I like this approach because it allows me to provide access to the Session without having to clone it and allows the MutexGuard and RwLockReadGuard to be held as the user needs without allowing the user to access the RwLockReadGuard and poke around the rest of the entries in the HashMap.
Diffstat (limited to 'src/app.rs')
| -rw-r--r-- | src/app.rs | 37 |
1 files changed, 37 insertions, 0 deletions
diff --git a/src/app.rs b/src/app.rs new file mode 100644 index 0000000..43e2ac6 --- /dev/null +++ b/src/app.rs @@ -0,0 +1,37 @@ +//! Internal app logic. + +use crate::session::Session; +use std::collections::HashMap; +use std::sync::{Mutex, MutexGuard, RwLock}; + +/// Provider of the state that Tabletop Ambulator needs to keep track of. +/// +/// Provides the app state, including runtime data such as the active game +/// sessions. It provides access to relevant data through synchronization +/// primitives, but does not handle shared ownership; for that, you may +/// want to use a solution like [`std::sync::Arc`]. +#[derive(Debug, Default)] +pub struct AppState { + sessions: RwLock<HashMap<String, Mutex<Session>>>, +} + +impl AppState { + /// Creates a new `AppState`. + pub fn new() -> Self { + Self::default() + } + + /// Creates and stores a new [`Session`], which can later be accessed with [`with_session`]. + pub fn create_session(&self, id: String, name: String) { + let session = Mutex::new(Session::new(name)); + self.sessions.write().unwrap().insert(id, session); + } + + /// Finds a [`Session`] by the provided `id`. If the session exists, it is provided within a + /// [`MutexGuard`] to the supplied function. Returns the result of the function, or `None` if + /// there was no session with the supplied id. + pub fn with_session<T>(&self, id: &str, f: impl FnOnce(MutexGuard<Session>) -> T) -> Option<T> { + let sessions = self.sessions.read().unwrap(); + sessions.get(id).map(|session| f(session.lock().unwrap())) + } +} |
