Skip to main content

matchmaker/utils/
serde.rs

1use cli_boilerplate_automation::wbog;
2use serde::{Deserialize, Deserializer, Serialize};
3
4use crate::utils::string::resolve_escapes;
5
6#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7#[serde(untagged)]
8pub enum StringOrVec {
9    String(String),
10    Vec(Vec<String>),
11}
12impl Default for StringOrVec {
13    fn default() -> Self {
14        StringOrVec::String(String::new())
15    }
16}
17
18pub fn bounded_usize<'de, D, const MIN: usize, const MAX: usize>(d: D) -> Result<usize, D::Error>
19where
20    D: Deserializer<'de>,
21{
22    let v = usize::deserialize(d)?;
23    if v < MIN {
24        wbog!("{} exceeded the the limit of {} and was clamped.", v, MIN);
25        Ok(MIN)
26    } else if v > MAX {
27        wbog!("{} exceeded the the limit of {} and was clamped.", v, MAX);
28        Ok(MAX)
29    } else {
30        Ok(v)
31    }
32}
33
34pub fn escaped_opt_string<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
35where
36    D: serde::Deserializer<'de>,
37{
38    let opt = Option::<String>::deserialize(deserializer)?;
39    Ok(opt.map(|s| resolve_escapes(&s)))
40}
41
42pub fn escaped_opt_char<'de, D>(deserializer: D) -> Result<Option<char>, D::Error>
43where
44    D: serde::Deserializer<'de>,
45{
46    let opt = Option::<String>::deserialize(deserializer)?;
47    match opt {
48        Some(s) => {
49            let parsed = resolve_escapes(&s);
50            let mut chars = parsed.chars();
51            let first = chars
52                .next()
53                .ok_or_else(|| serde::de::Error::custom("escaped string is empty"))?;
54            if chars.next().is_some() {
55                return Err(serde::de::Error::custom(
56                    "escaped string must be exactly one character",
57                ));
58            }
59            Ok(Some(first))
60        }
61        None => Ok(None),
62    }
63}
64
65#[allow(unused)] // todo: lowpri: not sure why serialize needs this
66pub mod serde_duration_ms {
67    use serde::{Deserialize, Deserializer, Serializer};
68    use std::time::Duration;
69
70    pub fn serialize<S>(duration: &Duration, serializer: S) -> Result<S::Ok, S::Error>
71    where
72        S: Serializer,
73    {
74        let ms = duration.as_millis() as u64;
75        serializer.serialize_u64(ms)
76    }
77
78    pub fn deserialize<'de, D>(deserializer: D) -> Result<Duration, D::Error>
79    where
80        D: Deserializer<'de>,
81    {
82        let ms = u64::deserialize(deserializer)?;
83        Ok(Duration::from_millis(ms))
84    }
85}