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