concinnity_core/components/
gamepad_button.rs1macro_rules! button_label {
9 ($variant:ident) => {
10 stringify!($variant)
11 };
12 ($variant:ident => $label:literal) => {
13 $label
14 };
15}
16
17macro_rules! define_buttons {
18 ($($variant:ident $(=> $label:literal)?),* $(,)?) => {
19 #[derive(
26 Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize,
27 )]
28 #[expect(missing_docs, reason = "each variant is one button name; the vocabulary is documented on the enum")]
31 pub enum GamepadButton {
32 $($variant),*
33 }
34
35 impl GamepadButton {
36 pub const ALL: &'static [GamepadButton] = &[$(GamepadButton::$variant),*];
38
39 pub fn name(self) -> &'static str {
44 match self {
45 $(GamepadButton::$variant => stringify!($variant)),*
46 }
47 }
48
49 pub fn display_name(self) -> &'static str {
53 match self {
54 $(GamepadButton::$variant => button_label!($variant $(=> $label)?)),*
55 }
56 }
57 }
58 };
59}
60
61define_buttons! {
62 South,
63 East,
64 West,
65 North,
66 LeftShoulder => "LB",
67 RightShoulder => "RB",
68 LeftTrigger => "LT",
69 RightTrigger => "RT",
70 LeftStick => "L3",
71 RightStick => "R3",
72 DpadUp => "D-Up",
73 DpadDown => "D-Down",
74 DpadLeft => "D-Left",
75 DpadRight => "D-Right",
76 Start,
77 Select,
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83 use alloc::format;
84
85 #[test]
86 fn serializes_to_variant_name() {
87 let json = serde_json::to_string(&GamepadButton::South).unwrap();
88 assert_eq!(json, "\"South\"");
89 let back: GamepadButton = serde_json::from_str(&json).unwrap();
90 assert_eq!(back, GamepadButton::South);
91 }
92
93 #[test]
94 fn all_variants_cover_name_and_display() {
95 for &button in GamepadButton::ALL {
98 assert!(!button.name().is_empty(), "name empty for {button:?}");
99 assert!(
100 !button.display_name().is_empty(),
101 "display empty for {button:?}"
102 );
103 let json = serde_json::to_string(&button).unwrap();
104 assert_eq!(
105 json,
106 format!("\"{}\"", button.name()),
107 "serde vs name for {button:?}"
108 );
109 let back: GamepadButton = serde_json::from_str(&json).unwrap();
110 assert_eq!(back, button, "round trip for {button:?}");
111 }
112 }
113
114 #[test]
115 fn variant_names_are_unique() {
116 let mut seen = alloc::collections::BTreeSet::new();
119 for &button in GamepadButton::ALL {
120 assert!(
121 seen.insert(button.name()),
122 "duplicate name {}",
123 button.name()
124 );
125 }
126 assert_eq!(seen.len(), GamepadButton::ALL.len());
127 }
128}