1use crate::types::*;
7use crate::wire::{BayUid, DeviceUid, EdidProfile, LinkFeature, RcAction, RcKey, RcType};
8
9macro_rules! events {
22 (
23 device {
24 $( $(#[$dmeta:meta])* $dvariant:ident => $dmethod:ident ( $($darg:ident : $dty:ty),* ); )*
25 }
26 bay {
27 $( $(#[$bmeta:meta])* $bvariant:ident => $bmethod:ident ( $($barg:ident : $bty:ty),* ); )*
28 }
29 bay_and_device {
30 $( $(#[$lmeta:meta])* $lvariant:ident => $lmethod:ident ( $($larg:ident : $lty:ty),* ); )*
31 }
32 ) => {
33 #[derive(Clone, Debug, PartialEq)]
38 #[non_exhaustive]
39 pub enum Event {
40 $(
41 $(#[$dmeta])*
42 $dvariant {
43 device: DeviceUid,
45 $( #[allow(missing_docs)] $darg: $dty, )*
46 },
47 )*
48 $(
49 $(#[$bmeta])*
50 $bvariant {
51 bay: BayUid,
53 $( #[allow(missing_docs)] $barg: $bty, )*
54 },
55 )*
56 $(
57 $(#[$lmeta])*
58 $lvariant {
59 bay: BayUid,
61 $( #[allow(missing_docs)] $larg: $lty, )*
62 },
63 )*
64 }
65
66 #[allow(unused_variables)]
74 pub trait EventHandler: Send + Sync {
75 $(
76 $(#[$dmeta])*
77 fn $dmethod(&self, device: DeviceUid $(, $darg: $dty)*) {}
78 )*
79 $(
80 $(#[$bmeta])*
81 fn $bmethod(&self, bay: BayUid $(, $barg: $bty)*) {}
82 )*
83 $(
84 $(#[$lmeta])*
85 fn $lmethod(&self, bay: BayUid $(, $larg: $lty)*) {}
86 )*
87
88 fn on_device_update(&self, device: DeviceUid) {}
90
91 fn on_bay_update(&self, bay: BayUid) {}
93 }
94
95 impl Event {
96 pub(crate) fn dispatch(self, handler: &dyn EventHandler) {
99 match self {
100 $(
101 Self::$dvariant { device $(, $darg)* } => {
102 handler.$dmethod(device $(, $darg)*);
103 handler.on_device_update(device);
104 }
105 )*
106 $(
107 Self::$bvariant { bay $(, $barg)* } => {
108 handler.$bmethod(bay $(, $barg)*);
109 handler.on_bay_update(bay);
110 }
111 )*
112 $(
113 Self::$lvariant { bay $(, $larg)* } => {
114 handler.$lmethod(bay $(, $larg)*);
115 handler.on_bay_update(bay);
116 handler.on_device_update(bay.device);
117 }
118 )*
119 }
120 }
121 }
122 };
123}
124
125impl EventHandler for () {}
132
133events! {
134 device {
135 DeviceConfigChanged => on_device_config_changed();
137 DeviceConfigComplete => on_device_config_complete();
139 DeviceOnlineChanged => on_device_online_changed(online: bool);
141 DeviceTemperatureChanged => on_device_temperature_changed(temperatures: Vec<u8>);
143 FirmwareVersionChanged => on_firmware_version_changed(version: FirmwareVersion);
145 SystemStatusChanged => on_system_status_changed(status: u16, message: String);
147 NetworkStatusChanged => on_network_status_changed(status: NetworkPortStatus);
149 V2ipStatsChanged => on_v2ip_stats_changed(stats: V2ipDeviceStats);
151 V2ipSourcesChanged => on_v2ip_sources_changed(sources: Vec<V2ipStreamSources>);
153 V2ipDetailsChanged => on_v2ip_details_changed(details: DeviceV2ipDetails);
155 V2ipSinkChanged => on_v2ip_sink_changed(sink: DeviceV2ipSink);
157 MultiviewerStatusChanged => on_multiviewer_status_changed(status: MultiviewerStatus);
159 AudioEndpointsChanged => on_audio_endpoints_changed(endpoints: AudioEndpoints);
161 MeshMasterChanged => on_mesh_master_changed(master: DeviceUid);
163 TopologyChanged => on_topology_changed(topology: Vec<TopologyEntry>);
165 AmpDolbySettingsChanged => on_amp_dolby_settings_changed(settings: AmpDolbySettings);
167 PduStateChanged => on_pdu_state_changed(state: PduState);
169 SetupStatusChanged => on_setup_status_changed(completed: bool);
171 InstallerIdChanged => on_installer_id_changed(installer_id: u16);
173 TilingChanged => on_tiling_changed(tiling: V2ipTilingConfig);
175 RcSettingsChanged => on_rc_settings_changed(settings: RcSettings);
177 V2ipLinkChanged => on_v2ip_link_changed(target: DeviceUid);
179 MultiviewerCommand => on_multiviewer_command(command: MultiviewerCommand);
181 AudioSelectInput => on_audio_select_input(change: AudioChangeSource);
183 AudioEndpointMute => on_audio_endpoint_mute(endpoint: u16, muted: bool);
185 AudioEndpointTrigger => on_audio_endpoint_trigger(endpoint: u16, active: bool);
187 AudioEndpointVolume => on_audio_endpoint_volume(endpoint: u16, volume: u32);
189 DiscoverRequest => on_discover_request();
191 SetRouteRequested => on_set_route_requested(request: SetRouteRequest);
193 EdidRequested => on_edid_requested(request: EdidRequest);
195 EdidReceived => on_edid_received(edid: EdidRecord);
197 BayNameChangeRequested => on_bay_name_change_requested(change: BayNameChange);
199 EdidProfileChangeRequested => on_edid_profile_change_requested(change: EdidProfileChange);
201 RebootRequested => on_reboot_requested(request: RebootRequest);
203 FactoryResetRequested => on_factory_reset_requested(request: FactoryResetRequest);
205 MonitoringPulse => on_monitoring_pulse();
207 UpgradeFpgaRequested => on_upgrade_fpga_requested();
209 DetectBaysRequested => on_detect_bays_requested();
211 PowerSaveRequested => on_power_save_requested(request: V2ipPowerSaveRequest);
213 KeyTransmitRequested => on_key_transmit_requested(request: KeyTransmitRequest);
215 ActionTransmitRequested => on_action_transmit_requested(request: ActionTransmitRequest);
217 IrTransmitRequested => on_ir_transmit_requested(request: IrTransmitRequest);
219 BlacklistChanged => on_blacklist_changed(change: V2ipBlacklistChange);
221 VideoWallCommand => on_video_wall_command(command: VideoWallCommand);
223 }
224 bay {
225 BayRegistered => on_bay_registered();
227 VideoSourceChanged => on_video_source_changed(source: Option<BayUid>);
229 AudioSourceChanged => on_audio_source_changed(source: Option<BayUid>);
231 VolumeChanged => on_volume_changed(volume: VolumeMuteStatus);
233 PowerChanged => on_power_changed(power: PowerStatus);
235 NameChanged => on_name_changed(name: String);
237 SignalDetectedChanged => on_signal_detected_changed(detected: bool);
239 FaultyChanged => on_faulty_changed(faulty: bool);
241 HiddenChanged => on_hidden_changed(hidden: bool);
243 PoePoweredChanged => on_poe_powered_changed(powered: bool);
245 HdbtConnectedChanged => on_hdbt_connected_changed(connected: bool);
247 SignalTypeChanged => on_signal_type_changed(signal_type: String);
249 HpdDetectedChanged => on_hpd_detected_changed(detected: bool);
251 CecDetectedChanged => on_cec_detected_changed(detected: bool);
253 ArcChanged => on_arc_changed(arc: ArcStatus);
255 EdidProfileChanged => on_edid_profile_changed(profile: EdidProfile);
257 RcTypeChanged => on_rc_type_changed(rc_type: RcType);
259 KeyPressed => on_key_pressed(key: RcKey);
261 ActionReceived => on_action_received(action: RcAction);
263 MirrorStatusChanged => on_mirror_status_changed(mirror: BayMirrorStatus);
265 AmpZoneSettingsChanged => on_amp_zone_settings_changed(settings: AmpZoneSettings);
267 VolumeStep => on_volume_step(up: bool);
269 AudioClipped => on_audio_clip(clip: AudioClip);
271 IrCaptured => on_ir_captured(capture: IrCapture);
273 FilteredDevicesChanged => on_filtered_devices_changed(filtered: Vec<DeviceUid>);
275 AudioEndpointChanged => on_audio_endpoint_changed(endpoint: u8);
277 EncoderDisabledChanged => on_encoder_disabled_changed(disabled: bool);
279 DecoderDisabledChanged => on_decoder_disabled_changed(disabled: bool);
281 }
282 bay_and_device {
283 BayLinked => on_bay_linked(linked_serial: String, bay_name: String, features: LinkFeature);
290 BayUnlinked => on_bay_unlinked(linked_serial: String, bay_name: String);
295 }
296}
297
298#[cfg(test)]
299mod tests {
300 use super::*;
301 use std::sync::Mutex;
302
303 #[derive(Default)]
304 struct Recorder {
305 calls: Mutex<Vec<String>>,
306 }
307
308 impl Recorder {
309 fn record(&self, what: &str) {
310 if let Ok(mut calls) = self.calls.lock() {
311 calls.push(what.to_owned());
312 }
313 }
314
315 fn calls(&self) -> Vec<String> {
316 self.calls.lock().map(|c| c.clone()).unwrap_or_default()
317 }
318 }
319
320 impl EventHandler for Recorder {
321 fn on_power_changed(&self, _bay: BayUid, power: PowerStatus) {
322 self.record(&format!("power={power}"));
323 }
324
325 fn on_setup_status_changed(&self, _device: DeviceUid, completed: bool) {
326 self.record(&format!("setup={completed}"));
327 }
328
329 fn on_bay_update(&self, _bay: BayUid) {
330 self.record("bay_update");
331 }
332
333 fn on_device_update(&self, _device: DeviceUid) {
334 self.record("device_update");
335 }
336 }
337
338 const DEVICE: DeviceUid = DeviceUid::from_array([9; 16]);
339
340 #[test]
341 fn a_bay_event_fires_its_own_method_then_the_generic_bay_update() {
342 let recorder = Recorder::default();
343 Event::PowerChanged {
344 bay: BayUid::new(DEVICE, 3),
345 power: PowerStatus::On,
346 }
347 .dispatch(&recorder);
348 assert_eq!(recorder.calls(), ["power=on", "bay_update"]);
349 }
350
351 #[test]
352 fn a_device_event_fires_its_own_method_then_the_generic_device_update() {
353 let recorder = Recorder::default();
354 Event::SetupStatusChanged {
355 device: DEVICE,
356 completed: true,
357 }
358 .dispatch(&recorder);
359 assert_eq!(recorder.calls(), ["setup=true", "device_update"]);
360 }
361
362 #[test]
363 fn a_link_event_fires_both_generic_updates() {
364 let recorder = Recorder::default();
365 Event::BayUnlinked {
366 bay: BayUid::new(DEVICE, 3),
367 linked_serial: "AB1234".to_owned(),
368 bay_name: "Output 1".to_owned(),
369 }
370 .dispatch(&recorder);
371 assert_eq!(recorder.calls(), ["bay_update", "device_update"]);
372 }
373
374 #[test]
375 fn an_event_a_handler_does_not_name_still_fires_the_generic_update() {
376 let recorder = Recorder::default();
377 Event::MonitoringPulse { device: DEVICE }.dispatch(&recorder);
378 assert_eq!(
379 recorder.calls(),
380 ["device_update"],
381 "the default no-op must not swallow the fan-in"
382 );
383 }
384}