fission_core/
platform_haptics.rs1use crate::capability::{CapabilityType, OperationCapability};
4use serde::{Deserialize, Serialize};
5
6#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
7pub enum HapticImpactStyle {
8 Light,
9 #[default]
10 Medium,
11 Heavy,
12 Soft,
13 Rigid,
14}
15
16#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
17pub enum HapticNotificationKind {
18 #[default]
19 Success,
20 Warning,
21 Error,
22}
23
24#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
25pub struct HapticImpactRequest {
26 pub style: HapticImpactStyle,
27}
28
29#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
30pub struct HapticNotificationRequest {
31 pub kind: HapticNotificationKind,
32}
33
34#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
35pub struct HapticPatternStep {
36 pub duration_ms: u64,
37 pub intensity: u8,
38}
39
40#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
41pub struct HapticPatternRequest {
42 pub steps: Vec<HapticPatternStep>,
43}
44
45#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
46pub struct HapticError {
47 pub code: String,
48 pub message: String,
49}
50
51impl HapticError {
52 pub fn new(code: impl Into<String>, message: impl Into<String>) -> Self {
59 Self {
60 code: code.into(),
61 message: message.into(),
62 }
63 }
64
65 pub fn unsupported(operation: impl Into<String>) -> Self {
71 Self::new(
72 "unsupported",
73 format!(
74 "haptic operation `{}` is not supported by this host",
75 operation.into()
76 ),
77 )
78 }
79}
80
81pub struct HapticImpactCapability;
82impl OperationCapability for HapticImpactCapability {
83 type Request = HapticImpactRequest;
84 type Ok = ();
85 type Err = HapticError;
86}
87
88pub struct HapticNotificationCapability;
89impl OperationCapability for HapticNotificationCapability {
90 type Request = HapticNotificationRequest;
91 type Ok = ();
92 type Err = HapticError;
93}
94
95pub struct HapticSelectionCapability;
96impl OperationCapability for HapticSelectionCapability {
97 type Request = ();
98 type Ok = ();
99 type Err = HapticError;
100}
101
102pub struct HapticPatternCapability;
103impl OperationCapability for HapticPatternCapability {
104 type Request = HapticPatternRequest;
105 type Ok = ();
106 type Err = HapticError;
107}
108
109pub const HAPTIC_IMPACT: CapabilityType<HapticImpactCapability> =
110 CapabilityType::new("fission.haptics.impact");
111pub const HAPTIC_NOTIFICATION: CapabilityType<HapticNotificationCapability> =
112 CapabilityType::new("fission.haptics.notification");
113pub const HAPTIC_SELECTION: CapabilityType<HapticSelectionCapability> =
114 CapabilityType::new("fission.haptics.selection");
115pub const HAPTIC_PATTERN: CapabilityType<HapticPatternCapability> =
116 CapabilityType::new("fission.haptics.pattern");
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121
122 #[test]
123 fn haptic_requests_round_trip() {
124 let request = HapticPatternRequest {
125 steps: vec![
126 HapticPatternStep {
127 duration_ms: 20,
128 intensity: 128,
129 },
130 HapticPatternStep {
131 duration_ms: 40,
132 intensity: 255,
133 },
134 ],
135 };
136 let bytes = serde_json::to_vec(&request).unwrap();
137 let decoded: HapticPatternRequest = serde_json::from_slice(&bytes).unwrap();
138 assert_eq!(decoded, request);
139 }
140}