Преглед изворни кода

conf/terminal: fix serde of ProgressSpinnerSequence

If ProgressSpinnerSequence / progress_spinner_sequence had a value of
just an array of strings, it could not be parsed correctly. Fix that
with a custom serde impl and also add unit tests.

Signed-off-by: Manos Pitsidianakis <manos@pitsidianak.is>
Manos Pitsidianakis пре 8 месеци
родитељ
комит
25f0a3f814
2 измењених фајлова са 148 додато и 3 уклоњено
  1. 80 3
      meli/src/conf/terminal.rs
  2. 68 0
      meli/src/conf/tests.rs

+ 80 - 3
meli/src/conf/terminal.rs

@@ -120,19 +120,96 @@ impl DotAddressable for TerminalSettings {
     }
 }
 
-#[derive(Clone, Debug, Deserialize, Serialize)]
-#[serde(untagged)]
+#[derive(Clone, Debug, Eq, PartialEq)]
 pub enum ProgressSpinnerSequence {
     Integer(usize),
     Custom {
         frames: Vec<String>,
-        #[serde(default = "interval_ms_val")]
         interval_ms: u64,
     },
 }
 
+impl ProgressSpinnerSequence {
+    pub const fn interval_ms(&self) -> u64 {
+        match self {
+            Self::Integer(_) => interval_ms_val(),
+            Self::Custom {
+                frames: _,
+                interval_ms,
+            } => *interval_ms,
+        }
+    }
+}
+
+use serde::{Deserialize, Deserializer, Serialize, Serializer};
+
 const fn interval_ms_val() -> u64 {
     crate::utilities::ProgressSpinner::INTERVAL_MS
 }
 
 impl DotAddressable for ProgressSpinnerSequence {}
+
+impl<'de> Deserialize<'de> for ProgressSpinnerSequence {
+    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        #[derive(Clone, Debug, Deserialize, Serialize)]
+        #[serde(untagged)]
+        enum Inner {
+            Integer(usize),
+            Frames(Vec<String>),
+            Custom {
+                frames: Vec<String>,
+                #[serde(default = "interval_ms_val")]
+                interval_ms: u64,
+            },
+        }
+        let s = <Inner>::deserialize(deserializer)?;
+        match s {
+            Inner::Integer(i) => Ok(Self::Integer(i)),
+            Inner::Frames(frames) => Ok(Self::Custom {
+                frames,
+                interval_ms: interval_ms_val(),
+            }),
+            Inner::Custom {
+                frames,
+                interval_ms,
+            } => Ok(Self::Custom {
+                frames,
+                interval_ms,
+            }),
+        }
+    }
+}
+
+impl Serialize for ProgressSpinnerSequence {
+    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
+    where
+        S: Serializer,
+    {
+        match self {
+            Self::Integer(i) => serializer.serialize_i64(*i as i64),
+            Self::Custom {
+                frames,
+                interval_ms,
+            } => {
+                if *interval_ms == interval_ms_val() {
+                    use serde::ser::SerializeSeq;
+                    let mut seq = serializer.serialize_seq(Some(frames.len()))?;
+                    for element in frames {
+                        seq.serialize_element(element)?;
+                    }
+                    seq.end()
+                } else {
+                    use serde::ser::SerializeMap;
+
+                    let mut map = serializer.serialize_map(Some(2))?;
+                    map.serialize_entry("frames", frames)?;
+                    map.serialize_entry("interval_ms", interval_ms)?;
+                    map.end()
+                }
+            }
+        }
+    }
+}

+ 68 - 0
meli/src/conf/tests.rs

@@ -309,3 +309,71 @@ fn test_conf_theme_key_values() {
         }
     }
 }
+
+#[test]
+fn test_conf_progress_spinner_sequence() {
+    use crate::{conf::terminal::ProgressSpinnerSequence, utilities::ProgressSpinner};
+
+    let int_0 = ProgressSpinnerSequence::Integer(5);
+    assert_eq!(
+        toml::Value::try_from(&int_0).unwrap(),
+        toml::Value::try_from(5).unwrap()
+    );
+
+    let frames = ProgressSpinnerSequence::Custom {
+        frames: vec![
+            "⠁".to_string(),
+            "⠂".to_string(),
+            "⠄".to_string(),
+            "⡀".to_string(),
+            "⢀".to_string(),
+            "⠠".to_string(),
+            "⠐".to_string(),
+            "⠈".to_string(),
+        ],
+        interval_ms: ProgressSpinner::INTERVAL_MS,
+    };
+    assert_eq!(frames.interval_ms(), ProgressSpinner::INTERVAL_MS);
+    assert_eq!(
+        toml::Value::try_from(&frames).unwrap(),
+        toml::Value::try_from(["⠁", "⠂", "⠄", "⡀", "⢀", "⠠", "⠐", "⠈"]).unwrap()
+    );
+    let frames = ProgressSpinnerSequence::Custom {
+        frames: vec![
+            "⠁".to_string(),
+            "⠂".to_string(),
+            "⠄".to_string(),
+            "⡀".to_string(),
+            "⢀".to_string(),
+            "⠠".to_string(),
+            "⠐".to_string(),
+            "⠈".to_string(),
+        ],
+        interval_ms: ProgressSpinner::INTERVAL_MS + 1,
+    };
+    assert_eq!(
+        toml::Value::try_from(&frames).unwrap(),
+        toml::Value::try_from(indexmap::indexmap! {
+            "frames" => toml::Value::try_from(["⠁", "⠂", "⠄", "⡀", "⢀", "⠠", "⠐", "⠈"]).unwrap(),
+            "interval_ms" => toml::Value::try_from(ProgressSpinner::INTERVAL_MS + 1).unwrap()
+        })
+        .unwrap()
+    );
+    assert_eq!(
+        toml::from_str::<ProgressSpinnerSequence>(
+            r#"frames = ["⠁", "⠂", "⠄", "⡀", "⢀", "⠠", "⠐", "⠈"]
+interval_ms = 51"#
+        )
+        .unwrap(),
+        frames
+    );
+    assert_eq!(
+        toml::from_str::<indexmap::IndexMap<String, ProgressSpinnerSequence>>(
+            r#"sequence = { frames = ["⠁", "⠂", "⠄", "⡀", "⢀", "⠠", "⠐", "⠈"], interval_ms = 51 }"#
+        )
+        .unwrap(),
+        indexmap::indexmap! {
+            "sequence".to_string() => frames,
+        },
+    );
+}