rosu_mods/
serde.rs

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/// Struct to pass parameters into a [`GameMod`] deserialization.
113///
114/// This deserializes an integer as bitflags, a string as an acronym, or a map
115/// as a [`GameMod`] struct.
116///
117/// # Examples
118///
119/// If the [`GameMode`] is available, we can use the `Mode` variant.
120///
121/// ```
122/// use rosu_mods::{GameMod, GameMode, serde::GameModSeed, generated_mods::DifficultyAdjustMania};
123/// use serde::de;
124///
125/// // Note that `GameMod` does not implement `Deserialize` so we must
126/// // implement it manually.
127/// #[derive(serde::Deserialize)]
128/// struct MyStruct(
129///     #[serde(deserialize_with = "custom_deser")]
130///     GameMod
131/// );
132///
133/// // If this is our JSON...
134/// const JSON: &str = r#"{
135///     "mode": 3,
136///     "mod": {
137///         "acronym": "DA",
138///         "settings": {
139///             "drain_rate": 0.73
140///         }
141///     }
142/// }"#;
143///
144/// // ... our deserialization could look like this
145/// fn custom_deser<'de, D: de::Deserializer<'de>>(d: D) -> Result<GameMod, D::Error> {
146///     struct MyVisitor;
147///
148///     impl<'de> de::Visitor<'de> for MyVisitor {
149///         type Value = GameMod;
150///
151///         fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
152///             f.write_str("MyStruct")
153///         }
154///
155///         fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
156///         where
157///             A: de::MapAccess<'de>
158///         {
159///             let Some("mode") = map.next_key()? else {
160///                 return Err(de::Error::custom("expected `mode` as first field"));
161///             };
162///             let mode: GameMode = map.next_value()?;
163///             let Some("mod") = map.next_key()? else {
164///                 return Err(de::Error::custom("expected `mod` as second field"));
165///             };
166///
167///             let seed = GameModSeed::Mode { mode, deny_unknown_fields: true }; // <-
168///
169///             map.next_value_seed(seed)
170///         }
171///     }
172///
173///     d.deserialize_map(MyVisitor)
174/// }
175///
176/// let MyStruct(gamemod) = serde_json::from_str(JSON).unwrap();
177///
178/// assert_eq!(
179///     gamemod,
180///     GameMod::DifficultyAdjustMania(DifficultyAdjustMania {
181///         drain_rate: Some(0.73),
182///         ..Default::default()
183///     })
184/// );
185/// ```
186///
187/// If the mode is not available, we can use the `GuessMode` variant.
188///
189/// ```
190/// use rosu_mods::{GameMod, serde::GameModSeed, generated_mods::DifficultyAdjustTaiko};
191/// use serde::de;
192///
193/// #[derive(serde::Deserialize)]
194/// struct MyStruct(
195///     #[serde(deserialize_with = "custom_deser")]
196///     GameMod,
197/// );
198///
199/// // No mode in here so we can only guess
200/// const JSON: &str = r#"{
201///     "acronym": "DA",
202///     "settings": {
203///         "scroll_speed": 0.95
204///     }
205/// }"#;
206///
207/// // For the above JSON, the deserialization will try to use each mode's
208/// // `GameMod` variant for the `DA` acronym.
209/// // First it tries `DifficultyAdjustOsu` but sees that it has no
210/// // `scroll_speed` field so it continues on and succeeds for the taiko
211/// // variant. Note that if `deny_unknown_fields` was set to `false`, the
212/// // unknown `scroll_speed` field would not have caused an error when
213/// // deserializing the `DifficultyAdjustOsu`.
214///
215/// fn custom_deser<'de, D: de::Deserializer<'de>>(d: D) -> Result<GameMod, D::Error> {
216///     d.deserialize_map(GameModSeed::GuessMode { deny_unknown_fields: true })
217/// }
218///
219/// let MyStruct(gamemod) = serde_json::from_str(JSON).unwrap();
220///
221/// assert_eq!(
222///     gamemod,
223///     GameMod::DifficultyAdjustTaiko(DifficultyAdjustTaiko {
224///         scroll_speed: Some(0.95),
225///         ..Default::default()
226///     })
227/// );
228/// ```
229#[derive(Copy, Clone)]
230pub enum GameModSeed {
231    /// Use a specified [`GameMode`] for deserialization.
232    Mode {
233        mode: GameMode,
234        deny_unknown_fields: bool,
235    },
236    /// Try to deserialize for each [`GameMode`] and pick the first one that
237    /// doesn't fail.
238    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                // False positive from clippy
247                #[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/// Struct to pass parameters into a [`GameMods`] deserialization.
1030///
1031/// This deserializes an integer as bitflags, a string as acronyms, or a
1032/// sequence of [`GameMod`] data.
1033///
1034/// # Example
1035///
1036/// Let's define deserialization so that each contained [`GameMod`] should
1037/// belong to the same (guessed) [`GameMode`].
1038///
1039/// ```
1040/// use rosu_mods::{
1041///     generated_mods::{NoScopeCatch, UnknownMod},
1042///     serde::GameModsSeed,
1043///     Acronym, GameMod, GameMods,
1044/// };
1045/// use serde::de;
1046/// # use std::str::FromStr;
1047///
1048/// #[derive(serde::Deserialize)]
1049/// struct MyStruct(#[serde(deserialize_with = "custom_deser")] GameMods);
1050///
1051/// // A JSON sequence containing bitflags of mania's `FadeIn` mod, the
1052/// // `FloatingFruits` acronym, and `NoScope` data.
1053/// const JSON: &str = r#"[
1054///     1048576,
1055///     "FF",
1056///     {
1057///         "acronym": "NS",
1058///         "settings": {
1059///             "hidden_combo_count": 5
1060///         }
1061///     }
1062/// ]"#;
1063///
1064/// fn custom_deser<'de, D: de::Deserializer<'de>>(d: D) -> Result<GameMods, D::Error> {
1065///     // Here, we're defining that all deserialized mods should belong to the
1066///     // same mode.
1067///     d.deserialize_any(GameModsSeed::SameModeForEachMod { deny_unknown_fields: true })
1068/// }
1069///
1070/// // Although `FI` is not a `Catch` mod, the mode still has the most
1071/// // successfully deserialized mods (2) so that's the one that will be
1072/// // chosen.
1073///
1074/// let MyStruct(mods) = serde_json::from_str(JSON).unwrap();
1075/// let mut iter = mods.into_iter();
1076///
1077/// // The following order of mods is irrelevant here. The iterator just shows
1078/// // which mods are contained.
1079///
1080/// // `FF` was only specified as acronym so it only contains default values.
1081/// assert_eq!(
1082///     iter.next(),
1083///     Some(GameMod::FloatingFruitsCatch(Default::default()))
1084/// );
1085///
1086/// // For `NS` we did deserialize a field
1087/// assert_eq!(
1088///     iter.next(),
1089///     Some(GameMod::NoScopeCatch(NoScopeCatch {
1090///         hidden_combo_count: Some(5.0)
1091///     }))
1092/// );
1093///
1094/// // `FI` is not a `Catch` mod so it's deserialized as `UnknownCatch`
1095/// assert_eq!(
1096///     iter.next(),
1097///     Some(GameMod::UnknownCatch(UnknownMod {
1098///         acronym: Acronym::from_str("FI").unwrap()
1099///     }))
1100/// );
1101///
1102/// assert_eq!(iter.next(), None);
1103/// ```
1104///
1105/// Next, let's define deserialization so that each contained [`GameMod`]
1106/// picks the first [`GameMode`] that deserializes successfully.
1107///
1108/// ```
1109/// use rosu_mods::{serde::GameModsSeed, GameMod, GameMods};
1110/// use serde::de;
1111///
1112/// #[derive(serde::Deserialize)]
1113/// struct MyStruct(#[serde(deserialize_with = "custom_deser")] GameMods);
1114///
1115/// // The bitflags for `DT` and `FI`
1116/// const JSON: &str = "1048640";
1117///
1118/// fn custom_deser<'de, D: de::Deserializer<'de>>(d: D) -> Result<GameMods, D::Error> {
1119///     d.deserialize_any(GameModsSeed::AllowMultipleModes { deny_unknown_fields: true })
1120/// }
1121///
1122/// let MyStruct(mods) = serde_json::from_str(JSON).unwrap();
1123/// let mut iter = mods.into_iter();
1124///
1125/// // `Osu` is the first mode that successfully deserializes `DT`.
1126/// assert_eq!(
1127///     iter.next(),
1128///     Some(GameMod::DoubleTimeOsu(Default::default()))
1129/// );
1130///
1131/// // `FI` is only deserialized properly for `Mania`
1132/// assert_eq!(
1133///     iter.next(),
1134///     Some(GameMod::FadeInMania(Default::default()))
1135/// );
1136///
1137/// assert_eq!(iter.next(), None);
1138/// ```
1139#[derive(Copy, Clone)]
1140pub enum GameModsSeed {
1141    /// Use a specified [`GameMode`] for deserialization.
1142    Mode {
1143        mode: GameMode,
1144        deny_unknown_fields: bool,
1145    },
1146    /// For each contained [`GameMod`], try to deserialize it for each
1147    /// [`GameMode`] and pick the first one that doesn't fail.
1148    AllowMultipleModes { deny_unknown_fields: bool },
1149    /// For each [`GameMode`], deserialize each [`GameMod`] for that mode and
1150    /// pick the first one for which each [`GameMod`] succeeds deserialization
1151    /// or alternatively the mode with the least amount of unknown mods.
1152    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        // Collect raw mods for each mode and see which one has the most known
1338        // mods.
1339        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}