Skip to main content

leafwing_input_manager/user_input/
trait_serde.rs

1//! Serialization and deserialization of user input.
2
3use std::sync::RwLock;
4
5use bevy::app::App;
6use bevy::reflect::GetTypeRegistration;
7use serde::{Deserialize, Deserializer, Serialize, Serializer};
8use serde_flexitos::ser::require_erased_serialize_impl;
9use serde_flexitos::{Registry, serialize_trait_object};
10use std::sync::LazyLock;
11
12use super::{Axislike, Buttonlike, DualAxislike, TripleAxislike};
13use crate::typetag::{InfallibleMapRegistry, RegisterTypeTag};
14
15/// Registry of deserializers for [`Buttonlike`]s.
16static BUTTONLIKE_REGISTRY: LazyLock<RwLock<InfallibleMapRegistry<dyn Buttonlike>>> =
17    LazyLock::new(|| RwLock::new(InfallibleMapRegistry::new("Buttonlike")));
18
19/// Registry of deserializers for [`Axislike`]s.
20static AXISLIKE_REGISTRY: LazyLock<RwLock<InfallibleMapRegistry<dyn Axislike>>> =
21    LazyLock::new(|| RwLock::new(InfallibleMapRegistry::new("Axislike")));
22
23/// Registry of deserializers for [`DualAxislike`]s.
24static DUAL_AXISLIKE_REGISTRY: LazyLock<RwLock<InfallibleMapRegistry<dyn DualAxislike>>> =
25    LazyLock::new(|| RwLock::new(InfallibleMapRegistry::new("DualAxislike")));
26
27/// Registry of deserializers for [`TripleAxislike`]s.
28static TRIPLE_AXISLIKE_REGISTRY: LazyLock<RwLock<InfallibleMapRegistry<dyn TripleAxislike>>> =
29    LazyLock::new(|| RwLock::new(InfallibleMapRegistry::new("TripleAxislike")));
30
31/// A trait for registering inputs.
32pub trait RegisterUserInput {
33    /// Registers the specified [`Buttonlike`].
34    fn register_buttonlike_input<'de, T>(&mut self) -> &mut Self
35    where
36        T: RegisterTypeTag<'de, dyn Buttonlike> + GetTypeRegistration;
37
38    /// Registers the specified [`Axislike`].
39    fn register_axislike_input<'de, T>(&mut self) -> &mut Self
40    where
41        T: RegisterTypeTag<'de, dyn Axislike> + GetTypeRegistration;
42
43    /// Registers the specified [`DualAxislike`].
44    fn register_dual_axislike_input<'de, T>(&mut self) -> &mut Self
45    where
46        T: RegisterTypeTag<'de, dyn DualAxislike> + GetTypeRegistration;
47
48    /// Registers the specified [`TripleAxislike`].
49    fn register_triple_axislike_input<'de, T>(&mut self) -> &mut Self
50    where
51        T: RegisterTypeTag<'de, dyn TripleAxislike> + GetTypeRegistration;
52}
53
54impl RegisterUserInput for App {
55    fn register_buttonlike_input<'de, T>(&mut self) -> &mut Self
56    where
57        T: RegisterTypeTag<'de, dyn Buttonlike> + GetTypeRegistration,
58    {
59        let mut registry = BUTTONLIKE_REGISTRY.write().unwrap();
60        T::register_typetag(&mut registry);
61        self.register_type::<T>();
62        self
63    }
64
65    fn register_axislike_input<'de, T>(&mut self) -> &mut Self
66    where
67        T: RegisterTypeTag<'de, dyn Axislike> + GetTypeRegistration,
68    {
69        let mut registry = AXISLIKE_REGISTRY.write().unwrap();
70        T::register_typetag(&mut registry);
71        self.register_type::<T>();
72        self
73    }
74
75    fn register_dual_axislike_input<'de, T>(&mut self) -> &mut Self
76    where
77        T: RegisterTypeTag<'de, dyn DualAxislike> + GetTypeRegistration,
78    {
79        let mut registry = DUAL_AXISLIKE_REGISTRY.write().unwrap();
80        T::register_typetag(&mut registry);
81        self.register_type::<T>();
82        self
83    }
84
85    fn register_triple_axislike_input<'de, T>(&mut self) -> &mut Self
86    where
87        T: RegisterTypeTag<'de, dyn TripleAxislike> + GetTypeRegistration,
88    {
89        let mut registry = TRIPLE_AXISLIKE_REGISTRY.write().unwrap();
90        T::register_typetag(&mut registry);
91        self.register_type::<T>();
92        self
93    }
94}
95
96mod buttonlike {
97    use crate::user_input::Buttonlike;
98
99    use super::*;
100
101    impl Serialize for dyn Buttonlike + '_ {
102        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
103        where
104            S: Serializer,
105        {
106            // Check that `Buttonlike` has `erased_serde::Serialize` as a super trait,
107            // prmessageing infinite recursion at runtime.
108            const fn __check_erased_serialize_super_trait<T: ?Sized + Buttonlike>() {
109                require_erased_serialize_impl::<T>();
110            }
111            serialize_trait_object(serializer, self.reflect_short_type_path(), self)
112        }
113    }
114
115    impl<'de> Deserialize<'de> for Box<dyn Buttonlike> {
116        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
117        where
118            D: Deserializer<'de>,
119        {
120            let registry = BUTTONLIKE_REGISTRY.read().unwrap();
121            registry.deserialize_trait_object(deserializer)
122        }
123    }
124}
125
126mod axislike {
127    use crate::user_input::Axislike;
128
129    use super::*;
130
131    impl Serialize for dyn Axislike + '_ {
132        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
133        where
134            S: Serializer,
135        {
136            // Check that `Axislike` has `erased_serde::Serialize` as a super trait,
137            // prmessageing infinite recursion at runtime.
138            const fn __check_erased_serialize_super_trait<T: ?Sized + Axislike>() {
139                require_erased_serialize_impl::<T>();
140            }
141            serialize_trait_object(serializer, self.reflect_short_type_path(), self)
142        }
143    }
144
145    impl<'de> Deserialize<'de> for Box<dyn Axislike> {
146        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
147        where
148            D: Deserializer<'de>,
149        {
150            let registry = AXISLIKE_REGISTRY.read().unwrap();
151            registry.deserialize_trait_object(deserializer)
152        }
153    }
154}
155
156mod dualaxislike {
157    use crate::user_input::DualAxislike;
158
159    use super::*;
160
161    impl Serialize for dyn DualAxislike + '_ {
162        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
163        where
164            S: Serializer,
165        {
166            // Check that `DualAxislike` has `erased_serde::Serialize` as a super trait,
167            // prmessageing infinite recursion at runtime.
168            const fn __check_erased_serialize_super_trait<T: ?Sized + DualAxislike>() {
169                require_erased_serialize_impl::<T>();
170            }
171            serialize_trait_object(serializer, self.reflect_short_type_path(), self)
172        }
173    }
174
175    impl<'de> Deserialize<'de> for Box<dyn DualAxislike> {
176        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
177        where
178            D: Deserializer<'de>,
179        {
180            let registry = DUAL_AXISLIKE_REGISTRY.read().unwrap();
181            registry.deserialize_trait_object(deserializer)
182        }
183    }
184}
185
186mod tripleaxislike {
187    use crate::user_input::TripleAxislike;
188
189    use super::*;
190
191    impl Serialize for dyn TripleAxislike + '_ {
192        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
193        where
194            S: Serializer,
195        {
196            // Check that `TripleAxislike` has `erased_serde::Serialize` as a super trait,
197            // prmessageing infinite recursion at runtime.
198            const fn __check_erased_serialize_super_trait<T: ?Sized + TripleAxislike>() {
199                require_erased_serialize_impl::<T>();
200            }
201            serialize_trait_object(serializer, self.reflect_short_type_path(), self)
202        }
203    }
204
205    impl<'de> Deserialize<'de> for Box<dyn TripleAxislike> {
206        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
207        where
208            D: Deserializer<'de>,
209        {
210            let registry = TRIPLE_AXISLIKE_REGISTRY.read().unwrap();
211            registry.deserialize_trait_object(deserializer)
212        }
213    }
214}
215
216#[cfg(any(feature = "keyboard", feature = "mouse"))]
217#[cfg(test)]
218mod tests {
219    use crate as leafwing_input_manager;
220    use bevy::prelude::{App, Reflect};
221    use leafwing_input_manager_macros::Actionlike;
222
223    #[derive(Actionlike, Debug, Clone, PartialEq, Eq, Hash, Reflect)]
224    pub enum Action {
225        Foo,
226    }
227
228    fn register_input_deserializers() {
229        let mut app = App::new();
230
231        // Add the plugin to register input deserializers
232        app.add_plugins(crate::prelude::InputManagerPlugin::<Action>::default());
233    }
234
235    #[cfg(feature = "keyboard")]
236    #[test]
237    fn test_button_serde() {
238        use crate::prelude::Buttonlike;
239        use bevy::prelude::KeyCode;
240        use serde_test::{Token, assert_tokens};
241
242        register_input_deserializers();
243
244        let boxed_input: Box<dyn Buttonlike> = Box::new(KeyCode::KeyB);
245        assert_tokens(
246            &boxed_input,
247            &[
248                Token::Map { len: Some(1) },
249                Token::BorrowedStr("KeyCode"),
250                Token::UnitVariant {
251                    name: "KeyCode",
252                    variant: "KeyB",
253                },
254                Token::MapEnd,
255            ],
256        );
257    }
258
259    #[cfg(feature = "mouse")]
260    #[test]
261    fn test_mouse_button_serde() {
262        use bevy::prelude::MouseButton;
263        use serde_test::{Token, assert_tokens};
264
265        use crate::prelude::Buttonlike;
266
267        register_input_deserializers();
268
269        let boxed_input: Box<dyn Buttonlike> = Box::new(MouseButton::Left);
270        assert_tokens(
271            &boxed_input,
272            &[
273                Token::Map { len: Some(1) },
274                Token::BorrowedStr("MouseButton"),
275                Token::UnitVariant {
276                    name: "MouseButton",
277                    variant: "Left",
278                },
279                Token::MapEnd,
280            ],
281        );
282    }
283
284    #[cfg(feature = "mouse")]
285    #[test]
286    fn test_axis_serde() {
287        use crate::prelude::{Axislike, MouseScrollAxis};
288        use serde_test::{Token, assert_tokens};
289
290        register_input_deserializers();
291
292        let boxed_input: Box<dyn Axislike> = Box::new(MouseScrollAxis::Y);
293        assert_tokens(
294            &boxed_input,
295            &[
296                Token::Map { len: Some(1) },
297                Token::BorrowedStr("MouseScrollAxis"),
298                Token::Struct {
299                    name: "MouseScrollAxis",
300                    len: 3,
301                },
302                Token::BorrowedStr("axis"),
303                Token::Enum {
304                    name: "DualAxisType",
305                },
306                Token::Str("Y"),
307                Token::Unit,
308                Token::BorrowedStr("mouse_scroll_unit"),
309                Token::Enum {
310                    name: "MouseScrollUnit",
311                },
312                Token::Str("Pixel"),
313                Token::Unit,
314                Token::BorrowedStr("processors"),
315                Token::Seq { len: Some(0) },
316                Token::SeqEnd,
317                Token::StructEnd,
318                Token::MapEnd,
319            ],
320        );
321    }
322
323    #[cfg(feature = "mouse")]
324    #[test]
325    fn test_dual_axis_serde() {
326        use crate::prelude::{DualAxislike, MouseMove};
327        use serde_test::{Token, assert_tokens};
328
329        register_input_deserializers();
330
331        let boxed_input: Box<dyn DualAxislike> = Box::new(MouseMove::default());
332        assert_tokens(
333            &boxed_input,
334            &[
335                Token::Map { len: Some(1) },
336                Token::BorrowedStr("MouseMove"),
337                Token::Struct {
338                    name: "MouseMove",
339                    len: 1,
340                },
341                Token::Str("processors"),
342                Token::Seq { len: Some(0) },
343                Token::SeqEnd,
344                Token::StructEnd,
345                Token::MapEnd,
346            ],
347        );
348    }
349
350    #[cfg(feature = "keyboard")]
351    #[test]
352    fn test_triple_axis_serde() {
353        use crate::prelude::{TripleAxislike, VirtualDPad3D};
354        use bevy::prelude::KeyCode;
355        use serde_test::{Token, assert_tokens};
356
357        register_input_deserializers();
358
359        let boxed_input: Box<dyn TripleAxislike> = Box::new(VirtualDPad3D::new(
360            KeyCode::KeyW,
361            KeyCode::KeyS,
362            KeyCode::KeyA,
363            KeyCode::KeyD,
364            KeyCode::KeyF,
365            KeyCode::KeyB,
366        ));
367        assert_tokens(
368            &boxed_input,
369            &[
370                Token::Map { len: Some(1) },
371                Token::BorrowedStr("VirtualDPad3D"),
372                Token::Struct {
373                    name: "VirtualDPad3D",
374                    len: 6,
375                },
376                Token::Str("up"),
377                Token::Map { len: Some(1) },
378                Token::BorrowedStr("KeyCode"),
379                Token::UnitVariant {
380                    name: "KeyCode",
381                    variant: "KeyW",
382                },
383                Token::MapEnd,
384                Token::Str("down"),
385                Token::Map { len: Some(1) },
386                Token::BorrowedStr("KeyCode"),
387                Token::UnitVariant {
388                    name: "KeyCode",
389                    variant: "KeyS",
390                },
391                Token::MapEnd,
392                Token::Str("left"),
393                Token::Map { len: Some(1) },
394                Token::BorrowedStr("KeyCode"),
395                Token::UnitVariant {
396                    name: "KeyCode",
397                    variant: "KeyA",
398                },
399                Token::MapEnd,
400                Token::Str("right"),
401                Token::Map { len: Some(1) },
402                Token::BorrowedStr("KeyCode"),
403                Token::UnitVariant {
404                    name: "KeyCode",
405                    variant: "KeyD",
406                },
407                Token::MapEnd,
408                Token::Str("forward"),
409                Token::Map { len: Some(1) },
410                Token::BorrowedStr("KeyCode"),
411                Token::UnitVariant {
412                    name: "KeyCode",
413                    variant: "KeyF",
414                },
415                Token::MapEnd,
416                Token::Str("backward"),
417                Token::Map { len: Some(1) },
418                Token::BorrowedStr("KeyCode"),
419                Token::UnitVariant {
420                    name: "KeyCode",
421                    variant: "KeyB",
422                },
423                Token::MapEnd,
424                Token::StructEnd,
425                Token::MapEnd,
426            ],
427        );
428    }
429}