1#![cfg(feature = "serde")]
2
3use std::{
4 collections::BTreeMap,
5 error::Error as StdError,
6 fmt::{Debug, Display, Formatter, Result as FmtResult},
7 marker::PhantomData,
8 slice,
9 str::FromStr,
10};
11
12use serde::de::{
13 value::BorrowedStrDeserializer, Deserialize, DeserializeSeed, Deserializer, Error as DeError,
14 IgnoredAny, MapAccess, SeqAccess, Unexpected, Visitor,
15};
16
17use crate::{
18 generated_mods::{GameMod, UnknownMod},
19 order::GameModOrder,
20 Acronym, GameModIntermode, GameMode, GameMods, GameModsIntermode,
21};
22
23pub(crate) const BITFLAGS_U32: &str = "bitflags must be a u32";
24const EXPECTED_ACRONYM_FIRST: &str = "expected `acronym` as first field";
25
26const MODES: [GameMode; 4] = [
27 GameMode::Osu,
28 GameMode::Taiko,
29 GameMode::Catch,
30 GameMode::Mania,
31];
32
33pub(crate) struct GameModVisitor<M>(PhantomData<M>);
34
35impl<M> GameModVisitor<M> {
36 pub(crate) const fn new() -> Self {
37 Self(PhantomData)
38 }
39}
40
41pub(crate) struct DeserializedGameMod<'a, M> {
42 pub(crate) gamemod: M,
43 pub(crate) unknown_key: Option<UnknownKey<'a>>,
44}
45
46impl<'a, M> DeserializedGameMod<'a, M> {
47 pub(crate) fn new(
48 gamemod: M,
49 unknown_key: Option<MaybeOwnedStr<'a>>,
50 expected: &'static [&'static str],
51 ) -> Self {
52 Self {
53 gamemod,
54 unknown_key: UnknownKey::new(unknown_key, expected),
55 }
56 }
57}
58
59impl<'de, M> DeserializedGameMod<'de, M> {
60 pub(crate) fn try_deserialize_mod<D>(d: D, deny_unknown_fields: bool) -> Result<M, D::Error>
61 where
62 GameModVisitor<M>: Visitor<'de, Value = Self>,
63 D: Deserializer<'de>,
64 {
65 match d.deserialize_map(GameModVisitor::<M>::new()) {
66 Ok(Self { gamemod, .. }) if !deny_unknown_fields => Ok(gamemod),
67 Ok(Self {
68 gamemod,
69 unknown_key: None,
70 }) => Ok(gamemod),
71 Ok(Self {
72 unknown_key: Some(key),
73 ..
74 }) => Err(Self::unknown_field(&key)),
75 Err(err) => Err(err),
76 }
77 }
78
79 fn unknown_field<E: DeError>(unknown_key: &UnknownKey<'_>) -> E {
80 DeError::unknown_field(unknown_key.name.as_str(), unknown_key.expected)
81 }
82}
83
84pub(crate) struct UnknownKey<'a> {
85 pub(crate) name: MaybeOwnedStr<'a>,
86 pub(crate) expected: &'static [&'static str],
87}
88
89impl<'a> UnknownKey<'a> {
90 fn new(
91 unknown_key: Option<MaybeOwnedStr<'a>>,
92 expected: &'static [&'static str],
93 ) -> Option<Self> {
94 unknown_key.map(|name| Self { name, expected })
95 }
96}
97
98pub(crate) struct GameModSettingsSeed<'a> {
99 pub(crate) acronym: &'a str,
100 pub(crate) mode: GameMode,
101 pub(crate) deny_unknown_fields: bool,
102}
103
104impl<'de> DeserializeSeed<'de> for GameModSettingsSeed<'_> {
105 type Value = <Self as Visitor<'de>>::Value;
106
107 fn deserialize<D: Deserializer<'de>>(self, d: D) -> Result<Self::Value, D::Error> {
108 d.deserialize_map(self)
109 }
110}
111
112#[derive(Copy, Clone)]
230pub enum GameModSeed {
231 Mode {
233 mode: GameMode,
234 deny_unknown_fields: bool,
235 },
236 GuessMode { deny_unknown_fields: bool },
239}
240
241impl GameModSeed {
242 fn convert_acronym(self, acronym: &str) -> GameMod {
243 match self {
244 Self::Mode { mode, .. } => GameMod::new(acronym, mode),
245 Self::GuessMode { .. } => {
246 #[allow(clippy::needless_match)]
248 let unknown = match GameMod::new(acronym, GameMode::Osu) {
249 gamemod @ GameMod::UnknownOsu(_) => gamemod,
250 gamemod => return gamemod,
251 };
252
253 match GameMod::new(acronym, GameMode::Taiko) {
254 GameMod::UnknownTaiko(_) => {}
255 gamemod => return gamemod,
256 }
257
258 match GameMod::new(acronym, GameMode::Catch) {
259 GameMod::UnknownCatch(_) => {}
260 gamemod => return gamemod,
261 }
262
263 match GameMod::new(acronym, GameMode::Mania) {
264 GameMod::UnknownMania(_) => {}
265 gamemod => return gamemod,
266 }
267
268 unknown
269 }
270 }
271 }
272}
273
274impl<'de> DeserializeSeed<'de> for GameModSeed {
275 type Value = GameMod;
276
277 fn deserialize<D: Deserializer<'de>>(self, d: D) -> Result<Self::Value, D::Error> {
278 d.deserialize_any(self)
279 }
280}
281
282impl<'de> Visitor<'de> for GameModSeed {
283 type Value = GameMod;
284
285 fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult {
286 f.write_str("GameMod")
287 }
288
289 fn visit_str<E: DeError>(self, v: &str) -> Result<Self::Value, E> {
290 Ok(self.convert_acronym(v))
291 }
292
293 fn visit_string<E: DeError>(self, v: String) -> Result<Self::Value, E> {
294 self.visit_str(&v)
295 }
296
297 fn visit_i64<E: DeError>(self, v: i64) -> Result<Self::Value, E> {
298 let Ok(bits) = u32::try_from(v) else {
299 return Err(DeError::custom(BITFLAGS_U32));
300 };
301
302 self.visit_u32(bits)
303 }
304
305 fn visit_u32<E: DeError>(self, v: u32) -> Result<Self::Value, E> {
306 let acronym = GameModIntermode::try_from_bits(v)
307 .ok_or_else(|| DeError::custom(format!("invalid bits value `{v}`")))?
308 .acronym();
309
310 Ok(self.convert_acronym(acronym.as_str()))
311 }
312
313 fn visit_u64<E: DeError>(self, v: u64) -> Result<Self::Value, E> {
314 let Ok(bits) = u32::try_from(v) else {
315 return Err(DeError::custom(BITFLAGS_U32));
316 };
317
318 self.visit_u32(bits)
319 }
320
321 fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
322 let Some(GameModField::Acronym) = map.next_key()? else {
323 return Err(DeError::custom(EXPECTED_ACRONYM_FIRST));
324 };
325
326 let acronym_raw: MaybeOwnedStr<'de> = map.next_value()?;
327 let acronym = acronym_raw.as_str();
328 let mut gamemod = None;
329
330 while let Some(field) = map.next_key::<GameModField>()? {
331 if field == GameModField::Settings {
332 match self {
333 Self::Mode {
334 mode,
335 deny_unknown_fields,
336 } => {
337 let seed = GameModSettingsSeed {
338 acronym,
339 mode,
340 deny_unknown_fields,
341 };
342 gamemod = Some(map.next_value_seed(seed)?);
343 }
344 Self::GuessMode {
345 deny_unknown_fields,
346 } => {
347 let settings: GameModSettings<'de> = map.next_value()?;
348
349 gamemod = match settings.try_deserialize(acronym, deny_unknown_fields) {
350 gamemod @ Some(_) => gamemod,
351 None => Some(GameMod::UnknownOsu(UnknownMod {
352 acronym: <Acronym as FromStr>::from_str(acronym)
353 .unwrap_or(UnknownMod::UNKNOWN_ACRONYM),
354 })),
355 };
356 }
357 }
358 } else {
359 let _: IgnoredAny = map.next_value()?;
360 }
361 }
362
363 Ok(gamemod.unwrap_or_else(|| self.convert_acronym(acronym)))
364 }
365}
366
367pub(crate) struct GameModSettings<'a> {
368 fields: Vec<GameModSettingField<'a>>,
369}
370
371impl Debug for GameModSettings<'_> {
372 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
373 Debug::fmt(&self.fields, f)
374 }
375}
376
377impl<'de> Deserialize<'de> for GameModSettings<'de> {
378 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
379 struct FieldsVisitor;
380
381 impl<'de> Visitor<'de> for FieldsVisitor {
382 type Value = Vec<GameModSettingField<'de>>;
383
384 fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult {
385 f.write_str("GameModSettings")
386 }
387
388 fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
389 let mut fields = Vec::with_capacity(map.size_hint().unwrap_or(0));
390
391 while let Some((name, value)) = map.next_entry()? {
392 fields.push(GameModSettingField { name, value });
393 }
394
395 Ok(fields)
396 }
397 }
398
399 Ok(Self {
400 fields: d.deserialize_map(FieldsVisitor)?,
401 })
402 }
403}
404
405#[derive(Debug)]
406pub(crate) struct GameModDeserializeError {
407 msg: Box<str>,
408}
409
410impl Display for GameModDeserializeError {
411 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
412 f.write_str(&self.msg)
413 }
414}
415
416impl StdError for GameModDeserializeError {}
417
418impl DeError for GameModDeserializeError {
419 fn custom<T: Display>(msg: T) -> Self {
420 Self {
421 msg: msg.to_string().into_boxed_str(),
422 }
423 }
424}
425
426impl<'de> Deserializer<'de> for &'de GameModSettings<'_> {
427 type Error = GameModDeserializeError;
428
429 fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
430 where
431 V: Visitor<'de>,
432 {
433 self.deserialize_map(visitor)
434 }
435
436 fn deserialize_bool<V>(self, _: V) -> Result<V::Value, Self::Error>
437 where
438 V: Visitor<'de>,
439 {
440 unimplemented!()
441 }
442
443 fn deserialize_i8<V>(self, _: V) -> Result<V::Value, Self::Error>
444 where
445 V: Visitor<'de>,
446 {
447 unimplemented!()
448 }
449
450 fn deserialize_i16<V>(self, _: V) -> Result<V::Value, Self::Error>
451 where
452 V: Visitor<'de>,
453 {
454 unimplemented!()
455 }
456
457 fn deserialize_i32<V>(self, _: V) -> Result<V::Value, Self::Error>
458 where
459 V: Visitor<'de>,
460 {
461 unimplemented!()
462 }
463
464 fn deserialize_i64<V>(self, _: V) -> Result<V::Value, Self::Error>
465 where
466 V: Visitor<'de>,
467 {
468 unimplemented!()
469 }
470
471 fn deserialize_u8<V>(self, _: V) -> Result<V::Value, Self::Error>
472 where
473 V: Visitor<'de>,
474 {
475 unimplemented!()
476 }
477
478 fn deserialize_u16<V>(self, _: V) -> Result<V::Value, Self::Error>
479 where
480 V: Visitor<'de>,
481 {
482 unimplemented!()
483 }
484
485 fn deserialize_u32<V>(self, _: V) -> Result<V::Value, Self::Error>
486 where
487 V: Visitor<'de>,
488 {
489 unimplemented!()
490 }
491
492 fn deserialize_u64<V>(self, _: V) -> Result<V::Value, Self::Error>
493 where
494 V: Visitor<'de>,
495 {
496 unimplemented!()
497 }
498
499 fn deserialize_f32<V>(self, _: V) -> Result<V::Value, Self::Error>
500 where
501 V: Visitor<'de>,
502 {
503 unimplemented!()
504 }
505
506 fn deserialize_f64<V>(self, _: V) -> Result<V::Value, Self::Error>
507 where
508 V: Visitor<'de>,
509 {
510 unimplemented!()
511 }
512
513 fn deserialize_char<V>(self, _: V) -> Result<V::Value, Self::Error>
514 where
515 V: Visitor<'de>,
516 {
517 unimplemented!()
518 }
519
520 fn deserialize_str<V>(self, _: V) -> Result<V::Value, Self::Error>
521 where
522 V: Visitor<'de>,
523 {
524 unimplemented!()
525 }
526
527 fn deserialize_string<V>(self, _: V) -> Result<V::Value, Self::Error>
528 where
529 V: Visitor<'de>,
530 {
531 unimplemented!()
532 }
533
534 fn deserialize_bytes<V>(self, _: V) -> Result<V::Value, Self::Error>
535 where
536 V: Visitor<'de>,
537 {
538 unimplemented!()
539 }
540
541 fn deserialize_byte_buf<V>(self, _: V) -> Result<V::Value, Self::Error>
542 where
543 V: Visitor<'de>,
544 {
545 unimplemented!()
546 }
547
548 fn deserialize_option<V>(self, _: V) -> Result<V::Value, Self::Error>
549 where
550 V: Visitor<'de>,
551 {
552 unimplemented!()
553 }
554
555 fn deserialize_unit<V>(self, _: V) -> Result<V::Value, Self::Error>
556 where
557 V: Visitor<'de>,
558 {
559 unimplemented!()
560 }
561
562 fn deserialize_unit_struct<V>(self, _: &'static str, _: V) -> Result<V::Value, Self::Error>
563 where
564 V: Visitor<'de>,
565 {
566 unimplemented!()
567 }
568
569 fn deserialize_newtype_struct<V>(self, _: &'static str, _: V) -> Result<V::Value, Self::Error>
570 where
571 V: Visitor<'de>,
572 {
573 unimplemented!()
574 }
575
576 fn deserialize_seq<V>(self, _: V) -> Result<V::Value, Self::Error>
577 where
578 V: Visitor<'de>,
579 {
580 unimplemented!()
581 }
582
583 fn deserialize_tuple<V>(self, _: usize, _: V) -> Result<V::Value, Self::Error>
584 where
585 V: Visitor<'de>,
586 {
587 unimplemented!()
588 }
589
590 fn deserialize_tuple_struct<V>(
591 self,
592 _: &'static str,
593 _: usize,
594 _: V,
595 ) -> Result<V::Value, Self::Error>
596 where
597 V: Visitor<'de>,
598 {
599 unimplemented!()
600 }
601
602 fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
603 where
604 V: Visitor<'de>,
605 {
606 let mut d = GameModSettingsMap {
607 fields: self.fields.iter(),
608 value: None,
609 };
610
611 visitor.visit_map(&mut d)
612 }
613
614 fn deserialize_struct<V>(
615 self,
616 _: &'static str,
617 _: &'static [&'static str],
618 visitor: V,
619 ) -> Result<V::Value, Self::Error>
620 where
621 V: Visitor<'de>,
622 {
623 self.deserialize_map(visitor)
624 }
625
626 fn deserialize_enum<V>(
627 self,
628 _: &'static str,
629 _: &'static [&'static str],
630 _: V,
631 ) -> Result<V::Value, Self::Error>
632 where
633 V: Visitor<'de>,
634 {
635 unimplemented!()
636 }
637
638 fn deserialize_identifier<V>(self, _: V) -> Result<V::Value, Self::Error>
639 where
640 V: Visitor<'de>,
641 {
642 unimplemented!()
643 }
644
645 fn deserialize_ignored_any<V>(self, _: V) -> Result<V::Value, Self::Error>
646 where
647 V: Visitor<'de>,
648 {
649 unimplemented!()
650 }
651}
652
653struct GameModSettingsMap<'de> {
654 fields: slice::Iter<'de, GameModSettingField<'de>>,
655 value: Option<&'de Value<'de>>,
656}
657
658impl<'de> MapAccess<'de> for GameModSettingsMap<'de> {
659 type Error = GameModDeserializeError;
660
661 fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
662 where
663 K: DeserializeSeed<'de>,
664 {
665 match self.fields.next() {
666 Some(field) => {
667 self.value = Some(&field.value);
668 let key_de = BorrowedStrDeserializer::new(field.name.as_str());
669
670 seed.deserialize(key_de).map(Some)
671 }
672 None => Ok(None),
673 }
674 }
675
676 fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
677 where
678 V: DeserializeSeed<'de>,
679 {
680 seed.deserialize(self.value.take().unwrap())
681 }
682
683 fn next_entry_seed<K, V>(
684 &mut self,
685 kseed: K,
686 vseed: V,
687 ) -> Result<Option<(K::Value, V::Value)>, Self::Error>
688 where
689 K: DeserializeSeed<'de>,
690 V: DeserializeSeed<'de>,
691 {
692 match self.fields.next() {
693 Some(field) => {
694 self.value.take();
695
696 let key_de = BorrowedStrDeserializer::new(field.name.as_str());
697 let key = kseed.deserialize(key_de)?;
698 let value = vseed.deserialize(&field.value)?;
699
700 Ok(Some((key, value)))
701 }
702 None => Ok(None),
703 }
704 }
705
706 fn size_hint(&self) -> Option<usize> {
707 let (lower, _) = self.fields.size_hint();
708
709 Some(lower)
710 }
711}
712
713struct GameModSettingField<'a> {
714 name: MaybeOwnedStr<'a>,
715 value: Value<'a>,
716}
717
718impl Debug for GameModSettingField<'_> {
719 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
720 f.debug_struct("GameModSettingField")
721 .field("name", &self.name.as_str())
722 .field("value", &self.value)
723 .finish()
724 }
725}
726
727enum Value<'de> {
728 Bool(bool),
729 Str(MaybeOwnedStr<'de>),
730 Number(f64),
731}
732
733impl Debug for Value<'_> {
734 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
735 match self {
736 Value::Bool(b) => Debug::fmt(b, f),
737 Value::Str(s) => Debug::fmt(s, f),
738 Value::Number(n) => Debug::fmt(n, f),
739 }
740 }
741}
742
743impl<'de> Deserialize<'de> for Value<'de> {
744 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
745 struct ValueVisitor;
746
747 impl<'de> Visitor<'de> for ValueVisitor {
748 type Value = Value<'de>;
749
750 fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult {
751 f.write_str("a bool, string, or number")
752 }
753
754 fn visit_bool<E: DeError>(self, v: bool) -> Result<Self::Value, E> {
755 Ok(Value::Bool(v))
756 }
757
758 fn visit_f32<E: DeError>(self, v: f32) -> Result<Self::Value, E> {
759 self.visit_f64(f64::from(v))
760 }
761
762 fn visit_f64<E: DeError>(self, v: f64) -> Result<Self::Value, E> {
763 Ok(Value::Number(v))
764 }
765
766 fn visit_u64<E: DeError>(self, v: u64) -> Result<Self::Value, E> {
767 self.visit_f64(v as f64)
768 }
769
770 fn visit_i64<E: DeError>(self, v: i64) -> Result<Self::Value, E> {
771 self.visit_f64(v as f64)
772 }
773
774 fn visit_borrowed_str<E: DeError>(self, v: &'de str) -> Result<Self::Value, E> {
775 Ok(Value::Str(MaybeOwnedStr::Borrowed(v)))
776 }
777
778 fn visit_str<E: DeError>(self, v: &str) -> Result<Self::Value, E> {
779 self.visit_string(v.to_owned())
780 }
781
782 fn visit_string<E: DeError>(self, v: String) -> Result<Self::Value, E> {
783 Ok(Value::Str(MaybeOwnedStr::Owned(v)))
784 }
785 }
786
787 d.deserialize_any(ValueVisitor)
788 }
789}
790
791impl<'de> Deserializer<'de> for &'de Value<'_> {
792 type Error = GameModDeserializeError;
793
794 fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
795 where
796 V: Visitor<'de>,
797 {
798 match self {
799 Value::Bool(v) => visitor.visit_bool(*v),
800 Value::Number(v) => visitor.visit_f64(*v),
801 Value::Str(v) => visitor.visit_borrowed_str(v.as_str()),
802 }
803 }
804
805 fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
806 where
807 V: Visitor<'de>,
808 {
809 match self {
810 Value::Bool(v) => visitor.visit_bool(*v),
811 Value::Number(v) => Err(DeError::invalid_type(Unexpected::Float(*v), &visitor)),
812 Value::Str(v) => Err(DeError::invalid_type(Unexpected::Str(v.as_str()), &visitor)),
813 }
814 }
815
816 fn deserialize_i8<V>(self, _: V) -> Result<V::Value, Self::Error>
817 where
818 V: Visitor<'de>,
819 {
820 unimplemented!()
821 }
822
823 fn deserialize_i16<V>(self, _: V) -> Result<V::Value, Self::Error>
824 where
825 V: Visitor<'de>,
826 {
827 unimplemented!()
828 }
829
830 fn deserialize_i32<V>(self, _: V) -> Result<V::Value, Self::Error>
831 where
832 V: Visitor<'de>,
833 {
834 unimplemented!()
835 }
836
837 fn deserialize_i64<V>(self, _: V) -> Result<V::Value, Self::Error>
838 where
839 V: Visitor<'de>,
840 {
841 unimplemented!()
842 }
843
844 fn deserialize_u8<V>(self, _: V) -> Result<V::Value, Self::Error>
845 where
846 V: Visitor<'de>,
847 {
848 unimplemented!()
849 }
850
851 fn deserialize_u16<V>(self, _: V) -> Result<V::Value, Self::Error>
852 where
853 V: Visitor<'de>,
854 {
855 unimplemented!()
856 }
857
858 fn deserialize_u32<V>(self, _: V) -> Result<V::Value, Self::Error>
859 where
860 V: Visitor<'de>,
861 {
862 unimplemented!()
863 }
864
865 fn deserialize_u64<V>(self, _: V) -> Result<V::Value, Self::Error>
866 where
867 V: Visitor<'de>,
868 {
869 unimplemented!()
870 }
871
872 fn deserialize_f32<V>(self, _: V) -> Result<V::Value, Self::Error>
873 where
874 V: Visitor<'de>,
875 {
876 unimplemented!()
877 }
878
879 fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
880 where
881 V: Visitor<'de>,
882 {
883 match self {
884 Value::Bool(v) => Err(DeError::invalid_type(Unexpected::Bool(*v), &visitor)),
885 Value::Number(v) => visitor.visit_f64(*v),
886 Value::Str(v) => Err(DeError::invalid_type(Unexpected::Str(v.as_str()), &visitor)),
887 }
888 }
889
890 fn deserialize_char<V>(self, _: V) -> Result<V::Value, Self::Error>
891 where
892 V: Visitor<'de>,
893 {
894 unimplemented!()
895 }
896
897 fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
898 where
899 V: Visitor<'de>,
900 {
901 match self {
902 Value::Bool(v) => Err(DeError::invalid_type(Unexpected::Bool(*v), &visitor)),
903 Value::Number(v) => Err(DeError::invalid_type(Unexpected::Float(*v), &visitor)),
904 Value::Str(v) => visitor.visit_borrowed_str(v.as_str()),
905 }
906 }
907
908 fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
909 where
910 V: Visitor<'de>,
911 {
912 self.deserialize_str(visitor)
913 }
914
915 fn deserialize_bytes<V>(self, _: V) -> Result<V::Value, Self::Error>
916 where
917 V: Visitor<'de>,
918 {
919 unimplemented!()
920 }
921
922 fn deserialize_byte_buf<V>(self, _: V) -> Result<V::Value, Self::Error>
923 where
924 V: Visitor<'de>,
925 {
926 unimplemented!()
927 }
928
929 fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
930 where
931 V: Visitor<'de>,
932 {
933 visitor.visit_some(self)
934 }
935
936 fn deserialize_unit<V>(self, _: V) -> Result<V::Value, Self::Error>
937 where
938 V: Visitor<'de>,
939 {
940 unimplemented!()
941 }
942
943 fn deserialize_unit_struct<V>(self, _: &'static str, _: V) -> Result<V::Value, Self::Error>
944 where
945 V: Visitor<'de>,
946 {
947 unimplemented!()
948 }
949
950 fn deserialize_newtype_struct<V>(self, _: &'static str, _: V) -> Result<V::Value, Self::Error>
951 where
952 V: Visitor<'de>,
953 {
954 unimplemented!()
955 }
956
957 fn deserialize_seq<V>(self, _: V) -> Result<V::Value, Self::Error>
958 where
959 V: Visitor<'de>,
960 {
961 unimplemented!()
962 }
963
964 fn deserialize_tuple<V>(self, _: usize, _: V) -> Result<V::Value, Self::Error>
965 where
966 V: Visitor<'de>,
967 {
968 unimplemented!()
969 }
970
971 fn deserialize_tuple_struct<V>(
972 self,
973 _: &'static str,
974 _: usize,
975 _: V,
976 ) -> Result<V::Value, Self::Error>
977 where
978 V: Visitor<'de>,
979 {
980 unimplemented!()
981 }
982
983 fn deserialize_map<V>(self, _: V) -> Result<V::Value, Self::Error>
984 where
985 V: Visitor<'de>,
986 {
987 unimplemented!()
988 }
989
990 fn deserialize_struct<V>(
991 self,
992 _: &'static str,
993 _: &'static [&'static str],
994 _: V,
995 ) -> Result<V::Value, Self::Error>
996 where
997 V: Visitor<'de>,
998 {
999 unimplemented!()
1000 }
1001
1002 fn deserialize_enum<V>(
1003 self,
1004 _: &'static str,
1005 _: &'static [&'static str],
1006 _: V,
1007 ) -> Result<V::Value, Self::Error>
1008 where
1009 V: Visitor<'de>,
1010 {
1011 unimplemented!()
1012 }
1013
1014 fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>
1015 where
1016 V: Visitor<'de>,
1017 {
1018 self.deserialize_str(visitor)
1019 }
1020
1021 fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
1022 where
1023 V: Visitor<'de>,
1024 {
1025 visitor.visit_unit()
1026 }
1027}
1028
1029#[derive(Copy, Clone)]
1140pub enum GameModsSeed {
1141 Mode {
1143 mode: GameMode,
1144 deny_unknown_fields: bool,
1145 },
1146 AllowMultipleModes { deny_unknown_fields: bool },
1149 SameModeForEachMod { deny_unknown_fields: bool },
1153}
1154
1155impl GameModsSeed {
1156 fn convert_intermode(self, intermode: &GameModsIntermode) -> GameMods {
1157 match self {
1158 Self::Mode { mode, .. } => intermode.with_mode(mode),
1159 Self::SameModeForEachMod { .. } => {
1160 for mode in MODES {
1161 if let Some(mods) = intermode.try_with_mode(mode) {
1162 return mods;
1163 }
1164 }
1165
1166 intermode.with_mode(GameMode::Osu)
1167 }
1168 Self::AllowMultipleModes { .. } => intermode
1169 .iter()
1170 .map(|gamemod| {
1171 let [osu, modes @ ..] = MODES;
1172 let osu = GameMod::new(gamemod.acronym().as_str(), osu);
1173
1174 if !matches!(osu, GameMod::UnknownOsu(_)) {
1175 return osu;
1176 }
1177
1178 for mode in modes {
1179 match GameMod::new(gamemod.acronym().as_str(), mode) {
1180 GameMod::UnknownTaiko(_)
1181 | GameMod::UnknownCatch(_)
1182 | GameMod::UnknownMania(_) => {}
1183 gamemod => return gamemod,
1184 }
1185 }
1186
1187 osu
1188 })
1189 .collect(),
1190 }
1191 }
1192}
1193
1194impl<'de> DeserializeSeed<'de> for GameModsSeed {
1195 type Value = GameMods;
1196
1197 fn deserialize<D: Deserializer<'de>>(self, d: D) -> Result<Self::Value, D::Error> {
1198 d.deserialize_any(self)
1199 }
1200}
1201
1202impl<'de> Visitor<'de> for GameModsSeed {
1203 type Value = GameMods;
1204
1205 fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult {
1206 f.write_str("GameMods")
1207 }
1208
1209 fn visit_str<E: DeError>(self, v: &str) -> Result<Self::Value, E> {
1210 let intermode = v.parse::<GameModsIntermode>().map_err(DeError::custom)?;
1211
1212 Ok(self.convert_intermode(&intermode))
1213 }
1214
1215 fn visit_string<E: DeError>(self, v: String) -> Result<Self::Value, E> {
1216 self.visit_str(&v)
1217 }
1218
1219 fn visit_i64<E: DeError>(self, v: i64) -> Result<Self::Value, E> {
1220 let Ok(bits) = u32::try_from(v) else {
1221 return Err(DeError::custom(BITFLAGS_U32));
1222 };
1223
1224 self.visit_u32(bits)
1225 }
1226
1227 fn visit_u32<E: DeError>(self, v: u32) -> Result<Self::Value, E> {
1228 let intermode = GameModsIntermode::from_bits(v);
1229
1230 Ok(self.convert_intermode(&intermode))
1231 }
1232
1233 fn visit_u64<E: DeError>(self, v: u64) -> Result<Self::Value, E> {
1234 let Ok(bits) = u32::try_from(v) else {
1235 return Err(DeError::custom(BITFLAGS_U32));
1236 };
1237
1238 self.visit_u32(bits)
1239 }
1240
1241 fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
1242 let mut inner = BTreeMap::new();
1243
1244 let seed = match self {
1245 Self::Mode {
1246 mode,
1247 deny_unknown_fields,
1248 } => GameModSeed::Mode {
1249 mode,
1250 deny_unknown_fields,
1251 },
1252 Self::AllowMultipleModes {
1253 deny_unknown_fields,
1254 } => GameModSeed::GuessMode {
1255 deny_unknown_fields,
1256 },
1257 Self::SameModeForEachMod {
1258 deny_unknown_fields,
1259 } => {
1260 let mut mods_raw = Vec::new();
1261
1262 let seed = GameModRawSeed {
1263 deny_unknown_fields,
1264 };
1265
1266 while let Some(gamemod) = seq.next_element_seed(seed)? {
1267 mods_raw.push(gamemod);
1268 }
1269
1270 return GameModRaw::convert_slice::<A::Error>(&mods_raw);
1271 }
1272 };
1273
1274 while let Some(gamemod) = seq.next_element_seed(seed)? {
1275 inner.insert(GameModOrder::from(&gamemod), gamemod);
1276 }
1277
1278 Ok(GameMods { inner })
1279 }
1280
1281 fn visit_map<A: MapAccess<'de>>(self, map: A) -> Result<Self::Value, A::Error> {
1282 let seed = match self {
1283 Self::Mode {
1284 mode,
1285 deny_unknown_fields,
1286 } => GameModSeed::Mode {
1287 mode,
1288 deny_unknown_fields,
1289 },
1290 Self::AllowMultipleModes {
1291 deny_unknown_fields,
1292 }
1293 | Self::SameModeForEachMod {
1294 deny_unknown_fields,
1295 } => GameModSeed::GuessMode {
1296 deny_unknown_fields,
1297 },
1298 };
1299
1300 let gamemod = seed.visit_map(map)?;
1301
1302 let mut mods = GameMods::new();
1303 mods.insert(gamemod);
1304
1305 Ok(mods)
1306 }
1307}
1308
1309pub(crate) enum GameModRaw<'a> {
1310 Bits(u32),
1311 Acronym(MaybeOwnedStr<'a>),
1312 Full {
1313 acronym: MaybeOwnedStr<'a>,
1314 settings: GameModSettings<'a>,
1315 deny_unknown_fields: bool,
1316 },
1317}
1318
1319impl Debug for GameModRaw<'_> {
1320 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
1321 match self {
1322 Self::Bits(bits) => write!(f, "{bits}"),
1323 Self::Acronym(acronym) => Debug::fmt(acronym, f),
1324 Self::Full {
1325 acronym, settings, ..
1326 } => f
1327 .debug_struct("GameMod")
1328 .field("acronym", &acronym.as_str())
1329 .field("settings", settings)
1330 .finish(),
1331 }
1332 }
1333}
1334
1335impl GameModRaw<'_> {
1336 fn convert_slice<E: DeError>(mods_raw: &[Self]) -> Result<GameMods, E> {
1337 let mut inner = BTreeMap::new();
1340 let mut best_known_count = 0;
1341
1342 'modes: for mode in MODES {
1343 let mut mods = BTreeMap::new();
1344
1345 for mod_raw in mods_raw.iter() {
1346 let Ok(gamemod) = mod_raw.try_convert::<E>(mode) else {
1347 continue 'modes;
1348 };
1349
1350 mods.insert(GameModOrder::from(&gamemod), gamemod);
1351 }
1352
1353 let known_count = mods
1354 .values()
1355 .filter(|gamemod| {
1356 !matches!(
1357 gamemod,
1358 GameMod::UnknownOsu(_)
1359 | GameMod::UnknownTaiko(_)
1360 | GameMod::UnknownCatch(_)
1361 | GameMod::UnknownMania(_)
1362 )
1363 })
1364 .count();
1365
1366 if known_count == mods_raw.len() {
1367 return Ok(GameMods { inner: mods });
1368 } else if known_count > best_known_count {
1369 best_known_count = known_count;
1370 inner = mods;
1371 }
1372 }
1373
1374 if best_known_count > 0 || mods_raw.is_empty() {
1375 Ok(GameMods { inner })
1376 } else {
1377 Err(E::custom(format!(
1378 "all modes failed to deserialize mods {mods_raw:?}"
1379 )))
1380 }
1381 }
1382
1383 fn try_convert<E: DeError>(&self, mode: GameMode) -> Result<GameMod, E> {
1384 match self {
1385 GameModRaw::Bits(bits) => GameModIntermode::try_from_bits(*bits)
1386 .ok_or_else(|| DeError::custom(format!("invalid bits value `{bits}`")))
1387 .map(|intermode| GameMod::new(intermode.acronym().as_str(), mode)),
1388 GameModRaw::Acronym(acronym) => Ok(GameMod::new(acronym.as_str(), mode)),
1389 GameModRaw::Full {
1390 acronym,
1391 settings,
1392 deny_unknown_fields,
1393 } => GameModSettingsSeed {
1394 acronym: acronym.as_str(),
1395 mode,
1396 deny_unknown_fields: *deny_unknown_fields,
1397 }
1398 .deserialize(settings)
1399 .map_err(DeError::custom),
1400 }
1401 }
1402}
1403
1404#[derive(Copy, Clone)]
1405pub(crate) struct GameModRawSeed {
1406 pub(crate) deny_unknown_fields: bool,
1407}
1408
1409impl<'de> DeserializeSeed<'de> for GameModRawSeed {
1410 type Value = GameModRaw<'de>;
1411
1412 fn deserialize<D: Deserializer<'de>>(self, d: D) -> Result<Self::Value, D::Error> {
1413 d.deserialize_any(self)
1414 }
1415}
1416
1417impl<'de> Visitor<'de> for GameModRawSeed {
1418 type Value = GameModRaw<'de>;
1419
1420 fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult {
1421 f.write_str("GameMod")
1422 }
1423
1424 fn visit_i64<E: DeError>(self, v: i64) -> Result<Self::Value, E> {
1425 let bits = u32::try_from(v).map_err(|_| DeError::custom(BITFLAGS_U32))?;
1426
1427 self.visit_u32(bits)
1428 }
1429
1430 fn visit_u32<E: DeError>(self, v: u32) -> Result<Self::Value, E> {
1431 Ok(GameModRaw::Bits(v))
1432 }
1433
1434 fn visit_u64<E: DeError>(self, v: u64) -> Result<Self::Value, E> {
1435 let bits = u32::try_from(v).map_err(|_| DeError::custom(BITFLAGS_U32))?;
1436
1437 self.visit_u32(bits)
1438 }
1439
1440 fn visit_borrowed_str<E: DeError>(self, v: &'de str) -> Result<Self::Value, E> {
1441 Ok(GameModRaw::Acronym(MaybeOwnedStr::Borrowed(v)))
1442 }
1443
1444 fn visit_str<E: DeError>(self, v: &str) -> Result<Self::Value, E> {
1445 self.visit_string(v.to_owned())
1446 }
1447
1448 fn visit_string<E: DeError>(self, v: String) -> Result<Self::Value, E> {
1449 Ok(GameModRaw::Acronym(MaybeOwnedStr::Owned(v)))
1450 }
1451
1452 fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
1453 let Some(GameModField::Acronym) = map.next_key()? else {
1454 return Err(DeError::custom(EXPECTED_ACRONYM_FIRST));
1455 };
1456
1457 let acronym: MaybeOwnedStr<'de> = map.next_value()?;
1458
1459 loop {
1460 match map.next_key::<GameModField>()? {
1461 Some(GameModField::Settings) => {
1462 let settings: GameModSettings<'de> = map.next_value()?;
1463
1464 while map.next_entry::<GameModField, IgnoredAny>()?.is_some() {}
1465
1466 return Ok(GameModRaw::Full {
1467 acronym,
1468 settings,
1469 deny_unknown_fields: self.deny_unknown_fields,
1470 });
1471 }
1472 Some(_) => {
1473 let _: IgnoredAny = map.next_value()?;
1474 }
1475 None => return Ok(GameModRaw::Acronym(acronym)),
1476 }
1477 }
1478 }
1479}
1480
1481#[derive(Copy, Clone, PartialEq, Eq)]
1482enum GameModField {
1483 Acronym,
1484 Settings,
1485 Other,
1486}
1487
1488impl<'de> Deserialize<'de> for GameModField {
1489 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
1490 struct GameModFieldVisitor;
1491
1492 impl Visitor<'_> for GameModFieldVisitor {
1493 type Value = GameModField;
1494
1495 fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult {
1496 f.write_str("identifier")
1497 }
1498
1499 fn visit_str<E: DeError>(self, v: &str) -> Result<Self::Value, E> {
1500 let field = match v {
1501 "acronym" => GameModField::Acronym,
1502 "settings" => GameModField::Settings,
1503 _ => GameModField::Other,
1504 };
1505
1506 Ok(field)
1507 }
1508
1509 fn visit_string<E: DeError>(self, v: String) -> Result<Self::Value, E> {
1510 self.visit_str(&v)
1511 }
1512 }
1513
1514 d.deserialize_identifier(GameModFieldVisitor)
1515 }
1516}
1517
1518pub(crate) enum MaybeOwnedStr<'a> {
1519 Borrowed(&'a str),
1520 Owned(String),
1521}
1522
1523impl Debug for MaybeOwnedStr<'_> {
1524 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
1525 match self {
1526 Self::Borrowed(s) => Debug::fmt(s, f),
1527 Self::Owned(s) => Debug::fmt(s, f),
1528 }
1529 }
1530}
1531
1532impl MaybeOwnedStr<'_> {
1533 #[expect(
1534 clippy::missing_const_for_fn,
1535 reason = "false positive; fix when `String::as_str` is const"
1536 )]
1537 pub(crate) fn as_str(&self) -> &str {
1538 match self {
1539 MaybeOwnedStr::Borrowed(a) => a,
1540 MaybeOwnedStr::Owned(a) => a,
1541 }
1542 }
1543}
1544
1545impl<'de> Deserialize<'de> for MaybeOwnedStr<'de> {
1546 fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
1547 struct AcronymRawVisitor;
1548
1549 impl<'de> Visitor<'de> for AcronymRawVisitor {
1550 type Value = MaybeOwnedStr<'de>;
1551
1552 fn expecting(&self, f: &mut Formatter<'_>) -> FmtResult {
1553 f.write_str("string")
1554 }
1555
1556 fn visit_borrowed_str<E: DeError>(self, v: &'de str) -> Result<Self::Value, E> {
1557 Ok(MaybeOwnedStr::Borrowed(v))
1558 }
1559
1560 fn visit_str<E: DeError>(self, v: &str) -> Result<Self::Value, E> {
1561 self.visit_string(v.to_owned())
1562 }
1563
1564 fn visit_string<E: DeError>(self, v: String) -> Result<Self::Value, E> {
1565 Ok(MaybeOwnedStr::Owned(v))
1566 }
1567 }
1568
1569 d.deserialize_str(AcronymRawVisitor)
1570 }
1571}
1572
1573#[cfg(test)]
1574mod tests {
1575 use serde_json::Deserializer;
1576
1577 use crate::generated_mods::{
1578 AccuracyChallengeOsu, AccuracyChallengeTaiko, DifficultyAdjustTaiko,
1579 };
1580
1581 use super::*;
1582
1583 #[test]
1584 fn deser_mod_bits() {
1585 let json = "64";
1586
1587 let mut d = Deserializer::from_str(json);
1588 let osu_dt = GameModSeed::GuessMode {
1589 deny_unknown_fields: true,
1590 }
1591 .deserialize(&mut d)
1592 .unwrap();
1593 assert_eq!(osu_dt, GameMod::DoubleTimeOsu(Default::default()));
1594
1595 let mut d = Deserializer::from_str(json);
1596 let taiko_dt = GameModSeed::Mode {
1597 mode: GameMode::Taiko,
1598 deny_unknown_fields: true,
1599 }
1600 .deserialize(&mut d)
1601 .unwrap();
1602 assert_eq!(taiko_dt, GameMod::DoubleTimeTaiko(Default::default()));
1603 }
1604
1605 #[test]
1606 fn deser_mod_bits_fail() {
1607 let json = "2147483648";
1608
1609 let mut d = Deserializer::from_str(json);
1610 let err = GameModSeed::GuessMode {
1611 deny_unknown_fields: true,
1612 }
1613 .deserialize(&mut d);
1614 assert!(err.is_err());
1615
1616 let mut d = Deserializer::from_str(json);
1617 let err = GameModSeed::Mode {
1618 mode: GameMode::Mania,
1619 deny_unknown_fields: true,
1620 }
1621 .deserialize(&mut d);
1622 assert!(err.is_err());
1623 }
1624
1625 #[test]
1626 fn deser_mod_acronym() {
1627 let json = r#""AS""#;
1628
1629 let mut d = Deserializer::from_str(json);
1630 let osu_as = GameModSeed::GuessMode {
1631 deny_unknown_fields: true,
1632 }
1633 .deserialize(&mut d)
1634 .unwrap();
1635 assert_eq!(osu_as, GameMod::AdaptiveSpeedOsu(Default::default()));
1636
1637 let mut d = Deserializer::from_str(json);
1638 let taiko_as = GameModSeed::Mode {
1639 mode: GameMode::Taiko,
1640 deny_unknown_fields: true,
1641 }
1642 .deserialize(&mut d)
1643 .unwrap();
1644 assert_eq!(taiko_as, GameMod::AdaptiveSpeedTaiko(Default::default()));
1645
1646 let mut d = Deserializer::from_str(json);
1647 let catch_unknown = GameModSeed::Mode {
1648 mode: GameMode::Catch,
1649 deny_unknown_fields: true,
1650 }
1651 .deserialize(&mut d)
1652 .unwrap();
1653 assert_eq!(
1654 catch_unknown,
1655 GameMod::UnknownCatch(UnknownMod {
1656 acronym: "AS".parse().unwrap()
1657 })
1658 );
1659 }
1660
1661 #[test]
1662 fn deser_mod_data() {
1663 let json = r#"{
1664 "acronym": "AC",
1665 "settings": {
1666 "minimum_accuracy": 12.34,
1667 "accuracy_judge_mode": "my string",
1668 "restart": false
1669 }
1670 }"#;
1671
1672 let mut d = Deserializer::from_str(json);
1673 let osu_ac = GameModSeed::GuessMode {
1674 deny_unknown_fields: true,
1675 }
1676 .deserialize(&mut d)
1677 .unwrap();
1678 assert_eq!(
1679 osu_ac,
1680 GameMod::AccuracyChallengeOsu(AccuracyChallengeOsu {
1681 minimum_accuracy: Some(12.34),
1682 accuracy_judge_mode: Some(String::from("my string")),
1683 restart: Some(false),
1684 })
1685 );
1686
1687 let mut d = Deserializer::from_str(json);
1688 let taiko_ac = GameModSeed::Mode {
1689 mode: GameMode::Taiko,
1690 deny_unknown_fields: true,
1691 }
1692 .deserialize(&mut d)
1693 .unwrap();
1694 assert_eq!(
1695 taiko_ac,
1696 GameMod::AccuracyChallengeTaiko(AccuracyChallengeTaiko {
1697 minimum_accuracy: Some(12.34),
1698 accuracy_judge_mode: Some(String::from("my string")),
1699 restart: Some(false),
1700 })
1701 );
1702 }
1703
1704 #[test]
1705 fn deser_mod_data_unknown_field() {
1706 let json = r#"{
1707 "acronym": "HD",
1708 "settings": {
1709 "unknown_field": true
1710 }
1711 }"#;
1712
1713 let mut d = Deserializer::from_str(json);
1714 let unknown_osu = GameModSeed::GuessMode {
1715 deny_unknown_fields: true,
1716 }
1717 .deserialize(&mut d)
1718 .unwrap();
1719 assert_eq!(
1720 unknown_osu,
1721 GameMod::UnknownOsu(UnknownMod {
1722 acronym: Acronym::from_str("HD").unwrap()
1723 })
1724 );
1725
1726 let mut d = Deserializer::from_str(json);
1727 let osu_hd = GameModSeed::GuessMode {
1728 deny_unknown_fields: false,
1729 }
1730 .deserialize(&mut d)
1731 .unwrap();
1732 assert_eq!(osu_hd, GameMod::HiddenOsu(Default::default()));
1733
1734 let mut d = Deserializer::from_str(json);
1735 let err = GameModSeed::Mode {
1736 mode: GameMode::Catch,
1737 deny_unknown_fields: true,
1738 }
1739 .deserialize(&mut d);
1740 assert!(err.is_err());
1741
1742 let mut d = Deserializer::from_str(json);
1743 let hd_catch = GameModSeed::Mode {
1744 mode: GameMode::Catch,
1745 deny_unknown_fields: false,
1746 }
1747 .deserialize(&mut d)
1748 .unwrap();
1749 assert_eq!(hd_catch, GameMod::HiddenCatch(Default::default()));
1750 }
1751
1752 #[test]
1753 fn deser_mod_data_invalid_type() {
1754 let json = r#"{
1755 "acronym": "DT",
1756 "settings": {
1757 "speed_change": "should be number; not string",
1758 }
1759 }"#;
1760
1761 let mut d = Deserializer::from_str(json);
1762 let err = GameModSeed::GuessMode {
1763 deny_unknown_fields: true,
1764 }
1765 .deserialize(&mut d);
1766 assert!(err.is_err());
1767
1768 let mut d = Deserializer::from_str(json);
1769 let err = GameModSeed::Mode {
1770 mode: GameMode::Catch,
1771 deny_unknown_fields: true,
1772 }
1773 .deserialize(&mut d);
1774 assert!(err.is_err());
1775 }
1776
1777 #[test]
1778 fn deser_mods_bits() {
1779 let json = "1048584";
1780
1781 let mut d = Deserializer::from_str(json);
1782 let mania_hdfi = GameModsSeed::SameModeForEachMod {
1783 deny_unknown_fields: true,
1784 }
1785 .deserialize(&mut d)
1786 .unwrap();
1787 let mut expected = GameMods::new();
1788 expected.insert(GameMod::HiddenMania(Default::default()));
1789 expected.insert(GameMod::FadeInMania(Default::default()));
1790 assert_eq!(mania_hdfi, expected);
1791
1792 let mut d = Deserializer::from_str(json);
1793 let osu_hd_mania_fi = GameModsSeed::AllowMultipleModes {
1794 deny_unknown_fields: true,
1795 }
1796 .deserialize(&mut d)
1797 .unwrap();
1798 let mut expected = GameMods::new();
1799 expected.insert(GameMod::HiddenOsu(Default::default()));
1800 expected.insert(GameMod::FadeInMania(Default::default()));
1801 assert_eq!(osu_hd_mania_fi, expected);
1802
1803 let mut d = Deserializer::from_str(json);
1804 let osu_hdfi = GameModsSeed::Mode {
1805 mode: GameMode::Osu,
1806 deny_unknown_fields: true,
1807 }
1808 .deserialize(&mut d)
1809 .unwrap();
1810 let mut expected = GameMods::new();
1811 expected.insert(GameMod::HiddenOsu(Default::default()));
1812 expected.insert(GameMod::UnknownOsu(UnknownMod {
1813 acronym: "FI".parse().unwrap(),
1814 }));
1815 assert_eq!(osu_hdfi, expected);
1816 }
1817
1818 #[test]
1819 fn deser_mods_unknown_bits() {
1820 let json = "2147483648";
1821
1822 let mut d = Deserializer::from_str(json);
1823 let mods = GameModsSeed::SameModeForEachMod {
1824 deny_unknown_fields: true,
1825 }
1826 .deserialize(&mut d)
1827 .unwrap();
1828 assert_eq!(mods.len(), 0);
1829
1830 let mut d = Deserializer::from_str(json);
1831 let mods = GameModsSeed::AllowMultipleModes {
1832 deny_unknown_fields: true,
1833 }
1834 .deserialize(&mut d)
1835 .unwrap();
1836 assert_eq!(mods.len(), 0);
1837
1838 let mut d = Deserializer::from_str(json);
1839 let mods = GameModsSeed::Mode {
1840 mode: GameMode::Mania,
1841 deny_unknown_fields: true,
1842 }
1843 .deserialize(&mut d)
1844 .unwrap();
1845 assert_eq!(mods.len(), 0);
1846 }
1847
1848 #[test]
1849 fn deser_mods_acronyms() {
1850 let json = r#""HDFI""#;
1851
1852 let mut d = Deserializer::from_str(json);
1853 let mania_hdfi = GameModsSeed::SameModeForEachMod {
1854 deny_unknown_fields: true,
1855 }
1856 .deserialize(&mut d)
1857 .unwrap();
1858 let mut expected = GameMods::new();
1859 expected.insert(GameMod::HiddenMania(Default::default()));
1860 expected.insert(GameMod::FadeInMania(Default::default()));
1861 assert_eq!(mania_hdfi, expected);
1862
1863 let mut d = Deserializer::from_str(json);
1864 let osu_hd_mania_fi = GameModsSeed::AllowMultipleModes {
1865 deny_unknown_fields: true,
1866 }
1867 .deserialize(&mut d)
1868 .unwrap();
1869 let mut expected = GameMods::new();
1870 expected.insert(GameMod::HiddenOsu(Default::default()));
1871 expected.insert(GameMod::FadeInMania(Default::default()));
1872 assert_eq!(osu_hd_mania_fi, expected);
1873
1874 let mut d = Deserializer::from_str(json);
1875 let osu_hdfi = GameModsSeed::Mode {
1876 mode: GameMode::Osu,
1877 deny_unknown_fields: true,
1878 }
1879 .deserialize(&mut d)
1880 .unwrap();
1881 let mut expected = GameMods::new();
1882 expected.insert(GameMod::HiddenOsu(Default::default()));
1883 expected.insert(GameMod::UnknownOsu(UnknownMod {
1884 acronym: "FI".parse().unwrap(),
1885 }));
1886 assert_eq!(osu_hdfi, expected);
1887 }
1888
1889 #[test]
1890 fn deser_mods_data() {
1891 let json = r#"[
1892 8,
1893 "FF",
1894 {
1895 "acronym": "WG"
1896 },
1897 {
1898 "acronym": "AC",
1899 "settings": {
1900 "minimum_accuracy": 12.34,
1901 "accuracy_judge_mode": "my string",
1902 "restart": false
1903 }
1904 }
1905 ]"#;
1906
1907 let mut d = Deserializer::from_str(json);
1908 let mods = GameModsSeed::SameModeForEachMod {
1909 deny_unknown_fields: true,
1910 }
1911 .deserialize(&mut d)
1912 .unwrap();
1913 let mut expected = GameMods::new();
1914 expected.insert(GameMod::HiddenOsu(Default::default()));
1915 expected.insert(GameMod::UnknownOsu(UnknownMod {
1916 acronym: "FF".parse().unwrap(),
1917 }));
1918 expected.insert(GameMod::WiggleOsu(Default::default()));
1919 expected.insert(GameMod::AccuracyChallengeOsu(AccuracyChallengeOsu {
1920 minimum_accuracy: Some(12.34),
1921 accuracy_judge_mode: Some(String::from("my string")),
1922 restart: Some(false),
1923 }));
1924 assert_eq!(mods, expected);
1925
1926 let mut d = Deserializer::from_str(json);
1927 let mods = GameModsSeed::AllowMultipleModes {
1928 deny_unknown_fields: true,
1929 }
1930 .deserialize(&mut d)
1931 .unwrap();
1932 let mut expected = GameMods::new();
1933 expected.insert(GameMod::HiddenOsu(Default::default()));
1934 expected.insert(GameMod::FloatingFruitsCatch(Default::default()));
1935 expected.insert(GameMod::WiggleOsu(Default::default()));
1936 expected.insert(GameMod::AccuracyChallengeOsu(AccuracyChallengeOsu {
1937 minimum_accuracy: Some(12.34),
1938 accuracy_judge_mode: Some(String::from("my string")),
1939 restart: Some(false),
1940 }));
1941 assert_eq!(mods, expected);
1942
1943 let mut d = Deserializer::from_str(json);
1944 let mods = GameModsSeed::Mode {
1945 mode: GameMode::Taiko,
1946 deny_unknown_fields: true,
1947 }
1948 .deserialize(&mut d)
1949 .unwrap();
1950 let mut expected = GameMods::new();
1951 expected.insert(GameMod::HiddenTaiko(Default::default()));
1952 expected.insert(GameMod::UnknownTaiko(UnknownMod {
1953 acronym: "FF".parse().unwrap(),
1954 }));
1955 expected.insert(GameMod::UnknownTaiko(UnknownMod {
1956 acronym: "WG".parse().unwrap(),
1957 }));
1958 expected.insert(GameMod::AccuracyChallengeTaiko(AccuracyChallengeTaiko {
1959 minimum_accuracy: Some(12.34),
1960 accuracy_judge_mode: Some(String::from("my string")),
1961 restart: Some(false),
1962 }));
1963 assert_eq!(mods, expected);
1964 }
1965
1966 #[test]
1967 fn deser_mods_single_data() {
1968 let json = r#"{
1969 "acronym": "FI"
1970 }"#;
1971
1972 let mut d = Deserializer::from_str(json);
1973 let mods = GameModsSeed::AllowMultipleModes {
1974 deny_unknown_fields: true,
1975 }
1976 .deserialize(&mut d)
1977 .unwrap();
1978 let mut expected = GameMods::new();
1979 expected.insert(GameMod::FadeInMania(Default::default()));
1980 assert_eq!(mods, expected);
1981
1982 let mut d = Deserializer::from_str(json);
1983 let mods = GameModsSeed::Mode {
1984 mode: GameMode::Taiko,
1985 deny_unknown_fields: true,
1986 }
1987 .deserialize(&mut d)
1988 .unwrap();
1989 let mut expected = GameMods::new();
1990 expected.insert(GameMod::UnknownTaiko(UnknownMod {
1991 acronym: "FI".parse().unwrap(),
1992 }));
1993 assert_eq!(mods, expected);
1994 }
1995
1996 #[test]
1997 fn deser_mods_data_unknown_fields() {
1998 let json = r#"[
1999 {
2000 "acronym": "DA",
2001 "settings": {
2002 "scroll_speed": 10
2003 }
2004 },
2005 {
2006 "acronym": "FI",
2007 "settings": {
2008 "unknown_field": true
2009 }
2010 }
2011 ]"#;
2012
2013 let mut d = Deserializer::from_str(json);
2014 let mods = GameModsSeed::AllowMultipleModes {
2015 deny_unknown_fields: true,
2016 }
2017 .deserialize(&mut d)
2018 .unwrap();
2019 let mut expected = GameMods::new();
2020 expected.insert(GameMod::DifficultyAdjustTaiko(DifficultyAdjustTaiko {
2021 scroll_speed: Some(10.0),
2022 ..Default::default()
2023 }));
2024 expected.insert(GameMod::UnknownOsu(UnknownMod {
2025 acronym: Acronym::from_str("FI").unwrap(),
2026 }));
2027 assert_eq!(mods, expected);
2028
2029 let mut d = Deserializer::from_str(json);
2030 let mods = GameModsSeed::Mode {
2031 mode: GameMode::Taiko,
2032 deny_unknown_fields: true,
2033 }
2034 .deserialize(&mut d)
2035 .unwrap();
2036 let mut expected = GameMods::new();
2037 expected.insert(GameMod::DifficultyAdjustTaiko(DifficultyAdjustTaiko {
2038 scroll_speed: Some(10.0),
2039 ..Default::default()
2040 }));
2041 expected.insert(GameMod::UnknownTaiko(UnknownMod {
2042 acronym: Acronym::from_str("FI").unwrap(),
2043 }));
2044 assert_eq!(mods, expected);
2045
2046 let mut d = Deserializer::from_str(json);
2047 let mods = GameModsSeed::AllowMultipleModes {
2048 deny_unknown_fields: false,
2049 }
2050 .deserialize(&mut d)
2051 .unwrap();
2052 let mut expected = GameMods::new();
2053 expected.insert(GameMod::DifficultyAdjustOsu(Default::default()));
2054 expected.insert(GameMod::FadeInMania(Default::default()));
2055 assert_eq!(mods, expected);
2056
2057 let mut d = Deserializer::from_str(json);
2058 let mods = GameModsSeed::Mode {
2059 mode: GameMode::Taiko,
2060 deny_unknown_fields: true,
2061 }
2062 .deserialize(&mut d)
2063 .unwrap();
2064 let mut expected = GameMods::new();
2065 expected.insert(GameMod::DifficultyAdjustTaiko(DifficultyAdjustTaiko {
2066 scroll_speed: Some(10.0),
2067 ..Default::default()
2068 }));
2069 expected.insert(GameMod::UnknownTaiko(UnknownMod {
2070 acronym: Acronym::from_str("FI").unwrap(),
2071 }));
2072 assert_eq!(mods, expected);
2073 }
2074
2075 #[test]
2076 fn deser_mods_same_success() {
2077 let json = r#"[
2078 {
2079 "acronym":"DA",
2080 "settings":{
2081 "scroll_speed":2
2082 }
2083 },
2084 {
2085 "acronym":"CS"
2086 }
2087 ]"#;
2088
2089 let mut d = Deserializer::from_str(json);
2090 let mods = GameModsSeed::SameModeForEachMod {
2091 deny_unknown_fields: true,
2092 }
2093 .deserialize(&mut d)
2094 .unwrap();
2095 let mut expected = GameMods::new();
2096 expected.insert(GameMod::DifficultyAdjustTaiko(DifficultyAdjustTaiko {
2097 scroll_speed: Some(2.0),
2098 ..Default::default()
2099 }));
2100 expected.insert(GameMod::ConstantSpeedTaiko(Default::default()));
2101 assert_eq!(mods, expected);
2102 }
2103
2104 #[test]
2105 fn deser_mods_same_fail() {
2106 let json = r#"[
2107 {
2108 "acronym":"DA",
2109 "settings":{
2110 "scroll_speed":2
2111 }
2112 },
2113 {
2114 "acronym":"EZ",
2115 "settings":{
2116 "retries":2
2117 }
2118 },
2119 "FI",
2120 256
2121 ]"#;
2122
2123 let mut d = Deserializer::from_str(json);
2124 let err = GameModsSeed::SameModeForEachMod {
2125 deny_unknown_fields: true,
2126 }
2127 .deserialize(&mut d)
2128 .unwrap_err();
2129 assert_eq!(err.to_string(), "all modes failed to deserialize mods [GameMod { acronym: \"DA\", settings: [GameModSettingField { name: \"scroll_speed\", value: 2.0 }] }, GameMod { acronym: \"EZ\", settings: [GameModSettingField { name: \"retries\", value: 2.0 }] }, \"FI\", 256] at line 16 column 9");
2130 }
2131}