1use crate::sys;
3use std::{
4 cell::RefCell,
5 ffi::{self, CString},
6 rc::Rc,
7 slice,
8};
9
10type CommBusCallback<'a> = Box<dyn FnMut(&str) + 'a>;
13
14#[derive(Default)]
16pub enum CommBusBroadcastFlags {
17 JS,
18 WASM,
19 WASMSelfCall,
20 #[default]
21 Default,
22 AllWASM,
23 All,
24}
25
26impl From<CommBusBroadcastFlags> for sys::FsCommBusBroadcastFlags {
27 fn from(value: CommBusBroadcastFlags) -> Self {
28 match value {
29 CommBusBroadcastFlags::JS => sys::FsCommBusBroadcastFlags_FsCommBusBroadcast_JS,
30 CommBusBroadcastFlags::WASM => sys::FsCommBusBroadcastFlags_FsCommBusBroadcast_Wasm,
31 CommBusBroadcastFlags::WASMSelfCall => {
32 sys::FsCommBusBroadcastFlags_FsCommBusBroadcast_WasmSelfCall
33 }
34 CommBusBroadcastFlags::Default => {
35 sys::FsCommBusBroadcastFlags_FsCommBusBroadcast_Default
36 }
37 CommBusBroadcastFlags::AllWASM => {
38 sys::FsCommBusBroadcastFlags_FsCommBusBroadcast_AllWasm
39 }
40 CommBusBroadcastFlags::All => sys::FsCommBusBroadcastFlags_FsCommBusBroadcast_All,
41 }
42 }
43}
44
45#[derive(Default)]
46pub struct CommBus<'a> {
47 events: Vec<Rc<RefCell<Option<CommBusEvent<'a>>>>>,
48}
49impl<'a> CommBus<'a> {
50 pub fn register(
54 &mut self,
55 event_name: &str,
56 callback: impl FnMut(&str) + 'a,
57 ) -> Option<Rc<RefCell<Option<CommBusEvent<'a>>>>> {
58 if let Some(event) = CommBusEvent::register(event_name, callback) {
59 let event = Rc::new(RefCell::new(Some(event)));
60 self.events.push(event.clone());
61 Some(event)
62 } else {
63 None
64 }
65 }
66
67 pub fn call(event_name: &str, args: &str, called: CommBusBroadcastFlags) -> bool {
70 if let (Ok(event_name), Ok(args_cstr)) = (CString::new(event_name), CString::new(args)) {
71 unsafe {
72 sys::fsCommBusCall(
73 event_name.as_ptr(),
74 args_cstr.as_ptr(),
75 (args.len() + 1) as ffi::c_uint,
76 called.into(),
77 )
78 }
79 } else {
80 false
81 }
82 }
83
84 pub fn unregister_all(&mut self) {
87 for event in &self.events {
88 event.take();
89 }
90 self.events.clear();
91 }
92}
93
94pub struct CommBusEvent<'a> {
96 event_name: CString,
97 callback: Box<CommBusCallback<'a>>,
98}
99impl<'a> CommBusEvent<'a> {
100 pub fn register(event_name: &str, callback: impl FnMut(&str) + 'a) -> Option<Self> {
102 let this = Self {
103 event_name: CString::new(event_name).ok()?,
104 callback: Box::new(Box::new(callback)),
105 };
106 let res = unsafe {
107 sys::fsCommBusRegister(
108 this.event_name.as_ptr(),
109 Some(Self::c_callback),
110 this.callback.as_ref() as *const _ as *mut _,
111 )
112 };
113 if res { Some(this) } else { None }
114 }
115
116 extern "C" fn c_callback(args: *const ffi::c_char, size: ffi::c_uint, ctx: *mut ffi::c_void) {
117 if !ctx.is_null() {
118 let (mut callback, args) = unsafe {
119 (
120 Box::from_raw(ctx as *mut CommBusCallback<'a>),
121 slice::from_raw_parts(args as *const u8, size as usize),
123 )
124 };
125 callback(&String::from_utf8_lossy(args));
126 Box::leak(callback);
128 }
129 }
130}
131impl Drop for CommBusEvent<'_> {
132 fn drop(&mut self) {
133 unsafe {
134 sys::fsCommBusUnregister(self.event_name.as_ptr(), Some(Self::c_callback));
135 }
136 }
137}