steamworks/callbacks/
mod.rs1pub use persona_state_change::*;
2
3use az::WrappingCast;
4use futures::Stream;
5use parking_lot::Mutex;
6use slotmap::DenseSlotMap;
7use std::convert::TryFrom;
8use steamworks_sys as sys;
9
10mod persona_state_change;
11
12pub(crate) type CallbackStorage<T> =
13 Mutex<DenseSlotMap<slotmap::DefaultKey, futures::channel::mpsc::UnboundedSender<T>>>;
14
15pub(crate) unsafe fn dispatch_callbacks(
16 callback_dispatchers: &CallbackDispatchers,
17 callback_msg: sys::CallbackMsg_t,
18) {
19 unsafe {
20 match callback_msg.m_iCallback.wrapping_cast() {
21 sys::PersonaStateChange_t_k_iCallback => callback_dispatchers
22 .persona_state_change
23 .dispatch(callback_msg.m_pubParam, callback_msg.m_cubParam),
24 sys::SteamShutdown_t_k_iCallback => callback_dispatchers
25 .steam_shutdown
26 .dispatch(callback_msg.m_pubParam, callback_msg.m_cubParam),
27 _ => {}
28 }
29 }
30}
31
32pub(crate) fn register_to_receive_callback<T: Clone + Send + 'static>(
33 dispatcher: &impl CallbackDispatcher<MappedCallbackData = T>,
34) -> impl Stream<Item = T> + Send {
35 let (tx, rx) = futures::channel::mpsc::unbounded();
36 dispatcher.storage().lock().insert(tx);
37 rx
38}
39
40#[derive(Debug, Default)]
41pub(crate) struct CallbackDispatchers {
42 pub(crate) persona_state_change: PersonaStateChangeDispatcher,
43 pub(crate) steam_shutdown: SteamShutdownDispatcher,
44}
45
46impl CallbackDispatchers {
47 pub(crate) fn new() -> Self {
48 Self::default()
49 }
50}
51
52pub(crate) trait CallbackDispatcher {
53 type RawCallbackData;
54 type MappedCallbackData: Clone + Send + 'static;
55
56 fn storage(&self) -> &CallbackStorage<Self::MappedCallbackData>;
57 fn map_callback_data(raw: &Self::RawCallbackData) -> Self::MappedCallbackData;
58
59 unsafe fn dispatch(&self, callback_data: *const u8, callback_data_len: i32) {
60 assert!(!callback_data.is_null());
61 assert_eq!(
62 callback_data.align_offset(align_of::<Self::RawCallbackData>()),
63 0
64 );
65 assert_eq!(
66 usize::try_from(callback_data_len).unwrap(),
67 size_of::<Self::RawCallbackData>()
68 );
69
70 let raw = unsafe { &*(callback_data as *const Self::RawCallbackData) };
71 let mapped = Self::map_callback_data(raw);
72
73 let mut storage = self.storage().lock();
74 storage.retain(|_key, tx| match tx.unbounded_send(mapped.clone()) {
75 Err(e) if e.is_disconnected() => false,
76 Err(e) => panic!("{}", e),
77 Ok(()) => true,
78 });
79 }
80}
81
82#[derive(Debug, Default)]
83pub(crate) struct SteamShutdownDispatcher(CallbackStorage<()>);
84
85impl CallbackDispatcher for SteamShutdownDispatcher {
86 type RawCallbackData = sys::SteamShutdown_t;
87 type MappedCallbackData = ();
88
89 fn storage(&self) -> &CallbackStorage<()> {
90 &self.0
91 }
92
93 fn map_callback_data(_raw: &sys::SteamShutdown_t) {}
94}