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::{Registry, serialize_trait_object};
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::{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}