fission_shell_winit/
haptics.rs1use fission_core::{
2 HapticError, HapticImpactRequest, HapticNotificationRequest, HapticPatternRequest,
3 HAPTIC_IMPACT, HAPTIC_NOTIFICATION, HAPTIC_PATTERN, HAPTIC_SELECTION,
4};
5use fission_shell::async_host::AsyncRegistry;
6use std::sync::{Arc, Mutex};
7
8pub trait HapticHost: Send + Sync + 'static {
10 fn impact(&self, request: HapticImpactRequest) -> Result<(), HapticError>;
12 fn notification(&self, request: HapticNotificationRequest) -> Result<(), HapticError>;
14 fn selection(&self) -> Result<(), HapticError>;
16 fn pattern(&self, request: HapticPatternRequest) -> Result<(), HapticError>;
18}
19
20#[derive(Debug, Default)]
21pub struct UnsupportedHapticHost;
22
23impl HapticHost for UnsupportedHapticHost {
24 fn impact(&self, _request: HapticImpactRequest) -> Result<(), HapticError> {
25 Err(HapticError::unsupported("impact"))
26 }
27
28 fn notification(&self, _request: HapticNotificationRequest) -> Result<(), HapticError> {
29 Err(HapticError::unsupported("notification"))
30 }
31
32 fn selection(&self) -> Result<(), HapticError> {
33 Err(HapticError::unsupported("selection"))
34 }
35
36 fn pattern(&self, _request: HapticPatternRequest) -> Result<(), HapticError> {
37 Err(HapticError::unsupported("pattern"))
38 }
39}
40
41#[derive(Debug, Default)]
42pub struct MemoryHapticHost {
43 calls: Arc<Mutex<Vec<String>>>,
44}
45
46impl MemoryHapticHost {
47 pub fn calls(&self) -> Vec<String> {
48 self.calls
49 .lock()
50 .map(|calls| calls.clone())
51 .unwrap_or_default()
52 }
53}
54
55impl HapticHost for MemoryHapticHost {
56 fn impact(&self, _request: HapticImpactRequest) -> Result<(), HapticError> {
57 self.calls.lock().unwrap().push("impact".into());
58 Ok(())
59 }
60
61 fn notification(&self, _request: HapticNotificationRequest) -> Result<(), HapticError> {
62 self.calls.lock().unwrap().push("notification".into());
63 Ok(())
64 }
65
66 fn selection(&self) -> Result<(), HapticError> {
67 self.calls.lock().unwrap().push("selection".into());
68 Ok(())
69 }
70
71 fn pattern(&self, _request: HapticPatternRequest) -> Result<(), HapticError> {
72 self.calls.lock().unwrap().push("pattern".into());
73 Ok(())
74 }
75}
76
77pub(crate) fn register_haptic_capabilities(
78 async_registry: &mut AsyncRegistry,
79 host: Arc<dyn HapticHost>,
80) {
81 let impact_host = host.clone();
82 async_registry.register_operation_capability(HAPTIC_IMPACT, move |request, _| {
83 let host = impact_host.clone();
84 async move { host.impact(request) }
85 });
86
87 let notification_host = host.clone();
88 async_registry.register_operation_capability(HAPTIC_NOTIFICATION, move |request, _| {
89 let host = notification_host.clone();
90 async move { host.notification(request) }
91 });
92
93 let selection_host = host.clone();
94 async_registry.register_operation_capability(HAPTIC_SELECTION, move |(), _| {
95 let host = selection_host.clone();
96 async move { host.selection() }
97 });
98
99 async_registry.register_operation_capability(HAPTIC_PATTERN, move |request, _| {
100 let host = host.clone();
101 async move { host.pattern(request) }
102 });
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108 use fission_core::HapticImpactStyle;
109
110 #[test]
111 fn unsupported_host_reports_errors() {
112 let host = UnsupportedHapticHost;
113 assert!(host.selection().is_err());
114 }
115
116 #[test]
117 fn memory_host_records_calls() {
118 let host = MemoryHapticHost::default();
119 host.impact(HapticImpactRequest {
120 style: HapticImpactStyle::Heavy,
121 })
122 .unwrap();
123 host.selection().unwrap();
124 assert_eq!(host.calls(), vec!["impact", "selection"]);
125 }
126}