Skip to main content

matchmaker/
config_types.rs

1use std::fmt;
2
3use cba::{bird::one_or_many, define_transparent_wrapper};
4use ratatui::widgets::Borders;
5
6use regex::Regex;
7
8use serde::{
9    Deserialize, Deserializer, Serialize, Serializer,
10    de::{self, Visitor},
11    ser::SerializeSeq,
12};
13
14#[derive(Clone, Copy, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
15pub enum HorizontalSeparator {
16    #[default]
17    None,
18    Empty,
19    Light,
20    Normal,
21    Heavy,
22    Dashed,
23}
24
25impl HorizontalSeparator {
26    pub fn as_str(self) -> &'static str {
27        match self {
28            Self::None => unreachable!(),
29            Self::Empty => " ",
30            Self::Light => "─", // U+2500
31            Self::Normal => "─",
32            Self::Heavy => "━",  // U+2501
33            Self::Dashed => "╌", // U+254C (box drawings light double dash)
34        }
35    }
36}
37
38#[derive(Debug, Default, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
39pub enum RowConnectionStyle {
40    #[default]
41    Disjoint,
42    Capped,
43    Full,
44}
45
46define_transparent_wrapper!(
47    #[derive(Copy, Clone, serde::Serialize, serde::Deserialize)]
48    #[serde(transparent)]
49    Count: u16 = 1
50);
51use ratatui::widgets::Padding as rPadding;
52
53define_transparent_wrapper!(
54    #[derive(Copy, Clone, Default)]
55    Padding: rPadding
56);
57
58#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Copy)]
59#[serde(untagged)]
60pub enum ShowCondition {
61    Bool(bool),
62    Free(u16),
63}
64impl Default for ShowCondition {
65    fn default() -> Self {
66        Self::Bool(false)
67    }
68}
69impl From<bool> for ShowCondition {
70    fn from(value: bool) -> Self {
71        ShowCondition::Bool(value)
72    }
73}
74
75impl From<u16> for ShowCondition {
76    fn from(value: u16) -> Self {
77        ShowCondition::Free(value)
78    }
79}
80
81// -----------------------------------------------------------------------------------------
82
83impl Serialize for Padding {
84    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
85    where
86        S: Serializer,
87    {
88        use serde::ser::SerializeSeq;
89        let padding = self;
90        if padding.top == padding.bottom
91            && padding.left == padding.right
92            && padding.top == padding.left
93        {
94            serializer.serialize_u16(padding.top)
95        } else if padding.top == padding.bottom && padding.left == padding.right {
96            let mut seq = serializer.serialize_seq(Some(2))?;
97            seq.serialize_element(&padding.left)?;
98            seq.serialize_element(&padding.top)?;
99            seq.end()
100        } else {
101            let mut seq = serializer.serialize_seq(Some(4))?;
102            seq.serialize_element(&padding.top)?;
103            seq.serialize_element(&padding.right)?;
104            seq.serialize_element(&padding.bottom)?;
105            seq.serialize_element(&padding.left)?;
106            seq.end()
107        }
108    }
109}
110
111impl<'de> Deserialize<'de> for Padding {
112    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
113    where
114        D: Deserializer<'de>,
115    {
116        use serde::de::Error;
117
118        let repr: Vec<u16> = one_or_many::deserialize(deserializer)?;
119
120        let inner = match repr.len() {
121            1 => {
122                let v = repr[0];
123                rPadding {
124                    top: v,
125                    right: v,
126                    bottom: v,
127                    left: v,
128                }
129            }
130            2 => {
131                let lr = repr[0];
132                let tb = repr[1];
133                rPadding {
134                    top: tb,
135                    right: lr,
136                    bottom: tb,
137                    left: lr,
138                }
139            }
140            4 => rPadding {
141                top: repr[0],
142                right: repr[1],
143                bottom: repr[2],
144                left: repr[3],
145            },
146            _ => {
147                return Err(D::Error::custom(
148                    "a number or an array of 1, 2, or 4 numbers",
149                ));
150            }
151        };
152
153        Ok(inner.into())
154    }
155}
156
157// ---------------------------------------------------------------------------------
158
159// define_restricted_wrapper!(
160//     #[derive(Clone, serde::Serialize, serde::Deserialize)]
161//     #[serde(transparent)]
162//     FormatString: String
163// );
164
165#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
166#[serde(rename_all = "lowercase")]
167pub enum Side {
168    Top,
169    Bottom,
170    Left,
171    #[default]
172    Right,
173}
174
175impl Side {
176    pub fn opposite(&self) -> Borders {
177        match self {
178            Side::Top => Borders::BOTTOM,
179            Side::Bottom => Borders::TOP,
180            Side::Left => Borders::RIGHT,
181            Side::Right => Borders::LEFT,
182        }
183    }
184}
185
186#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
187#[serde(rename_all = "lowercase")]
188pub enum CursorSetting {
189    None,
190    #[default]
191    Default,
192}
193
194#[derive(Default, Debug, Clone, PartialEq, serde::Serialize)]
195pub struct ColumnSetting {
196    pub filter: bool,
197    pub hidden: bool,
198    pub name: String,
199}
200
201#[derive(Default, Debug, Clone)]
202pub enum Split {
203    /// Split by delimiter. Supports regex.
204    Delimiter(Regex),
205    /// A sequence of regexes.
206    Regexes(Vec<Regex>),
207    /// No splitting.
208    #[default]
209    None,
210}
211
212impl PartialEq for Split {
213    fn eq(&self, other: &Self) -> bool {
214        match (self, other) {
215            (Split::Delimiter(r1), Split::Delimiter(r2)) => r1.as_str() == r2.as_str(),
216            (Split::Regexes(v1), Split::Regexes(v2)) => {
217                if v1.len() != v2.len() {
218                    return false;
219                }
220                v1.iter()
221                    .zip(v2.iter())
222                    .all(|(r1, r2)| r1.as_str() == r2.as_str())
223            }
224            (Split::None, Split::None) => true,
225            _ => false,
226        }
227    }
228}
229
230// ---------------------------------------------------------------------------------
231
232impl serde::Serialize for Split {
233    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
234    where
235        S: serde::Serializer,
236    {
237        match self {
238            Split::Delimiter(r) => serializer.serialize_str(r.as_str()),
239            Split::Regexes(rs) => {
240                let mut seq = serializer.serialize_seq(Some(rs.len()))?;
241                for r in rs {
242                    seq.serialize_element(r.as_str())?;
243                }
244                seq.end()
245            }
246            Split::None => serializer.serialize_none(),
247        }
248    }
249}
250
251impl<'de> Deserialize<'de> for Split {
252    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
253    where
254        D: Deserializer<'de>,
255    {
256        struct SplitVisitor;
257
258        impl<'de> Visitor<'de> for SplitVisitor {
259            type Value = Split;
260
261            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
262                formatter.write_str("string for delimiter or array of strings for regexes")
263            }
264
265            fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
266            where
267                E: de::Error,
268            {
269                // Try to compile single regex
270                Regex::new(value)
271                    .map(Split::Delimiter)
272                    .map_err(|e| E::custom(format!("Invalid regex: {}", e)))
273            }
274
275            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
276            where
277                A: serde::de::SeqAccess<'de>,
278            {
279                let mut regexes = Vec::new();
280                while let Some(s) = seq.next_element::<String>()? {
281                    let r = Regex::new(&s)
282                        .map_err(|e| de::Error::custom(format!("Invalid regex: {}", e)))?;
283                    regexes.push(r);
284                }
285                Ok(Split::Regexes(regexes))
286            }
287        }
288
289        deserializer.deserialize_any(SplitVisitor)
290    }
291}
292
293impl<'de> Deserialize<'de> for ColumnSetting {
294    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
295    where
296        D: Deserializer<'de>,
297    {
298        #[derive(Deserialize)]
299        #[serde(deny_unknown_fields)]
300        struct ColumnStruct {
301            #[serde(default = "default_true")]
302            filter: bool,
303            #[serde(default)]
304            hidden: bool,
305            name: String,
306        }
307
308        fn default_true() -> bool {
309            true
310        }
311
312        #[derive(Deserialize)]
313        #[serde(untagged)]
314        enum Input {
315            Str(String),
316            Obj(ColumnStruct),
317        }
318
319        match Input::deserialize(deserializer)? {
320            Input::Str(name) => Ok(ColumnSetting {
321                filter: true,
322                hidden: false,
323                name,
324            }),
325            Input::Obj(obj) => Ok(ColumnSetting {
326                filter: obj.filter,
327                hidden: obj.hidden,
328                name: obj.name,
329            }),
330        }
331    }
332}
333
334// ----------------------------------------------------------------------
335pub fn deserialize_string_or_char_as_double_width<'de, D, T>(deserializer: D) -> Result<T, D::Error>
336where
337    D: Deserializer<'de>,
338    T: From<String>,
339{
340    struct GenericVisitor<T> {
341        _marker: std::marker::PhantomData<T>,
342    }
343
344    impl<'de, T> Visitor<'de> for GenericVisitor<T>
345    where
346        T: From<String>,
347    {
348        type Value = T;
349
350        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
351            formatter.write_str("a string or single character")
352        }
353
354        fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
355        where
356            E: de::Error,
357        {
358            let s = if v.chars().count() == 1 {
359                let mut s = String::with_capacity(2);
360                s.push(v.chars().next().unwrap());
361                s.push(' ');
362                s
363            } else {
364                v.to_string()
365            };
366            Ok(T::from(s))
367        }
368
369        fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
370        where
371            E: de::Error,
372        {
373            self.visit_str(&v)
374        }
375    }
376
377    deserializer.deserialize_string(GenericVisitor {
378        _marker: std::marker::PhantomData,
379    })
380}
381
382// ----------------------------------------------------------------------------
383define_transparent_wrapper!(
384    #[derive(Clone, Eq, Serialize)]
385    StringValue: String
386
387);
388
389impl<'de> Deserialize<'de> for StringValue {
390    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
391    where
392        D: Deserializer<'de>,
393    {
394        struct Visitor;
395
396        impl<'de> de::Visitor<'de> for Visitor {
397            type Value = StringValue;
398
399            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
400                formatter.write_str("a string, number, or bool")
401            }
402
403            fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> {
404                Ok(StringValue(v.to_owned()))
405            }
406
407            fn visit_string<E>(self, v: String) -> Result<Self::Value, E> {
408                Ok(StringValue(v))
409            }
410
411            fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E> {
412                Ok(StringValue(v.to_string()))
413            }
414
415            fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E> {
416                Ok(StringValue(v.to_string()))
417            }
418
419            fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E> {
420                Ok(StringValue(v.to_string()))
421            }
422
423            fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E> {
424                Ok(StringValue(v.to_string()))
425            }
426        }
427
428        deserializer.deserialize_any(Visitor)
429    }
430}