1use 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::{serialize_trait_object, Registry};
10use std::sync::LazyLock;
11
12use super::{Axislike, Buttonlike, DualAxislike, TripleAxislike};
13use crate::typetag::{InfallibleMapRegistry, RegisterTypeTag};
14
15static BUTTONLIKE_REGISTRY: LazyLock<RwLock<InfallibleMapRegistry<dyn Buttonlike>>> =
17 LazyLock::new(|| RwLock::new(InfallibleMapRegistry::new("Buttonlike")));
18
19static AXISLIKE_REGISTRY: LazyLock<RwLock<InfallibleMapRegistry<dyn Axislike>>> =
21 LazyLock::new(|| RwLock::new(InfallibleMapRegistry::new("Axislike")));
22
23static DUAL_AXISLIKE_REGISTRY: LazyLock<RwLock<InfallibleMapRegistry<dyn DualAxislike>>> =
25 LazyLock::new(|| RwLock::new(InfallibleMapRegistry::new("DualAxislike")));
26
27static TRIPLE_AXISLIKE_REGISTRY: LazyLock<RwLock<InfallibleMapRegistry<dyn TripleAxislike>>> =
29 LazyLock::new(|| RwLock::new(InfallibleMapRegistry::new("TripleAxislike")));
30
31pub trait RegisterUserInput {
33 fn register_buttonlike_input<'de, T>(&mut self) -> &mut Self
35 where
36 T: RegisterTypeTag<'de, dyn Buttonlike> + GetTypeRegistration;
37
38 fn register_axislike_input<'de, T>(&mut self) -> &mut Self
40 where
41 T: RegisterTypeTag<'de, dyn Axislike> + GetTypeRegistration;
42
43 fn register_dual_axislike_input<'de, T>(&mut self) -> &mut Self
45 where
46 T: RegisterTypeTag<'de, dyn DualAxislike> + GetTypeRegistration;
47
48 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 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 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 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 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 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::{assert_tokens, Token};
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::{assert_tokens, Token};
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::{assert_tokens, Token};
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: 2,
301 },
302 Token::BorrowedStr("axis"),
303 Token::Enum {
304 name: "DualAxisType",
305 },
306 Token::Str("Y"),
307 Token::Unit,
308 Token::BorrowedStr("processors"),
309 Token::Seq { len: Some(0) },
310 Token::SeqEnd,
311 Token::StructEnd,
312 Token::MapEnd,
313 ],
314 );
315 }
316
317 #[cfg(feature = "mouse")]
318 #[test]
319 fn test_dual_axis_serde() {
320 use crate::prelude::{DualAxislike, MouseMove};
321 use serde_test::{assert_tokens, Token};
322
323 register_input_deserializers();
324
325 let boxed_input: Box<dyn DualAxislike> = Box::new(MouseMove::default());
326 assert_tokens(
327 &boxed_input,
328 &[
329 Token::Map { len: Some(1) },
330 Token::BorrowedStr("MouseMove"),
331 Token::Struct {
332 name: "MouseMove",
333 len: 1,
334 },
335 Token::Str("processors"),
336 Token::Seq { len: Some(0) },
337 Token::SeqEnd,
338 Token::StructEnd,
339 Token::MapEnd,
340 ],
341 );
342 }
343
344 #[cfg(feature = "keyboard")]
345 #[test]
346 fn test_triple_axis_serde() {
347 use crate::prelude::{TripleAxislike, VirtualDPad3D};
348 use bevy::prelude::KeyCode;
349 use serde_test::{assert_tokens, Token};
350
351 register_input_deserializers();
352
353 let boxed_input: Box<dyn TripleAxislike> = Box::new(VirtualDPad3D::new(
354 KeyCode::KeyW,
355 KeyCode::KeyS,
356 KeyCode::KeyA,
357 KeyCode::KeyD,
358 KeyCode::KeyF,
359 KeyCode::KeyB,
360 ));
361 assert_tokens(
362 &boxed_input,
363 &[
364 Token::Map { len: Some(1) },
365 Token::BorrowedStr("VirtualDPad3D"),
366 Token::Struct {
367 name: "VirtualDPad3D",
368 len: 6,
369 },
370 Token::Str("up"),
371 Token::Map { len: Some(1) },
372 Token::BorrowedStr("KeyCode"),
373 Token::UnitVariant {
374 name: "KeyCode",
375 variant: "KeyW",
376 },
377 Token::MapEnd,
378 Token::Str("down"),
379 Token::Map { len: Some(1) },
380 Token::BorrowedStr("KeyCode"),
381 Token::UnitVariant {
382 name: "KeyCode",
383 variant: "KeyS",
384 },
385 Token::MapEnd,
386 Token::Str("left"),
387 Token::Map { len: Some(1) },
388 Token::BorrowedStr("KeyCode"),
389 Token::UnitVariant {
390 name: "KeyCode",
391 variant: "KeyA",
392 },
393 Token::MapEnd,
394 Token::Str("right"),
395 Token::Map { len: Some(1) },
396 Token::BorrowedStr("KeyCode"),
397 Token::UnitVariant {
398 name: "KeyCode",
399 variant: "KeyD",
400 },
401 Token::MapEnd,
402 Token::Str("forward"),
403 Token::Map { len: Some(1) },
404 Token::BorrowedStr("KeyCode"),
405 Token::UnitVariant {
406 name: "KeyCode",
407 variant: "KeyF",
408 },
409 Token::MapEnd,
410 Token::Str("backward"),
411 Token::Map { len: Some(1) },
412 Token::BorrowedStr("KeyCode"),
413 Token::UnitVariant {
414 name: "KeyCode",
415 variant: "KeyB",
416 },
417 Token::MapEnd,
418 Token::StructEnd,
419 Token::MapEnd,
420 ],
421 );
422 }
423}