Drop NonEmpty for inline guards
The wrapper had no downstream consumer of its guarantee; is_empty
guards in Spec::from_lua keep the check and name the field.

Assisted-by: GLM-5.3 via pi
change rxzzqqmowxpylkpxwsrtzquyoxqyqqqm
commit accf615f1cd0feaec21bbf4d6159b484e464c8f9
author Alpha Chen <alpha@kejadlen.dev>
date
parent wkopkvmp
diff --git a/src/spec.rs b/src/spec.rs
index 01a8569..27fbd11 100644
--- a/src/spec.rs
+++ b/src/spec.rs
@@ -48,28 +48,6 @@ impl<'de> Deserialize<'de> for NonEmptyString {
     }
 }
 
-/// A non-empty sequence of values, rejected at deserialization time.
-#[derive(Debug)]
-pub(crate) struct NonEmpty<T>(Vec<T>);
-
-impl<T> NonEmpty<T> {
-    // Consumed once running configs lands.
-    #[allow(dead_code)]
-    pub(crate) fn as_slice(&self) -> &[T] {
-        &self.0
-    }
-}
-
-impl<'de, T: Deserialize<'de>> Deserialize<'de> for NonEmpty<T> {
-    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
-        let items = Vec::<T>::deserialize(deserializer)?;
-        if items.is_empty() {
-            return Err(serde::de::Error::custom("must not be empty"));
-        }
-        Ok(NonEmpty(items))
-    }
-}
-
 /// A flow: its name from the config and the Lua function to call when
 /// the parallax runs.
 #[derive(Debug)]
@@ -146,7 +124,7 @@ impl FromLua for Baseline {
 #[serde(deny_unknown_fields)]
 #[allow(dead_code)] // read by tests now, by the runner once run lands
 pub(crate) struct Schema {
-    pub(crate) viewports: NonEmpty<(NonEmptyString, NonZeroU32, NonZeroU32)>,
+    pub(crate) viewports: Vec<(NonEmptyString, NonZeroU32, NonZeroU32)>,
     pub(crate) server: Server,
 
     pub(crate) baseline: Option<IgnoredAny>,
@@ -160,7 +138,7 @@ pub(crate) struct Schema {
 #[serde(deny_unknown_fields)]
 #[allow(dead_code)] // read by tests now, by the runner once run lands
 pub(crate) struct Server {
-    pub(crate) cmd: NonEmpty<String>,
+    pub(crate) cmd: Vec<String>,
 
     #[serde(default = "default_timeout")]
     pub(crate) timeout: f64,
@@ -193,6 +171,12 @@ impl FromLua for Spec {
                     other => other,
                 }
             })?;
+        if schema.viewports.is_empty() {
+            return Err(mlua::Error::runtime("viewports must not be empty"));
+        }
+        if schema.server.cmd.is_empty() {
+            return Err(mlua::Error::runtime("server.cmd must not be empty"));
+        }
         let table = Table::from_lua(value, lua)?;
         let flows = Flows::from_lua(table.get("flows")?, lua)?;
         let baseline = Baseline::from_lua(table.get("baseline")?, lua)?;
@@ -239,7 +223,7 @@ mod tests {
     fn accepts_a_valid_config() {
         with_spec(&format!("{VIEWPORTS}, {SERVER}, {FLOWS}"), |lua, table| {
             let spec = spec(lua, table).expect("valid config");
-            assert_eq!(spec.schema.viewports.as_slice().len(), 1);
+            assert_eq!(spec.schema.viewports.len(), 1);
             assert_eq!(spec.flows.as_slice().len(), 1);
             assert_eq!(spec.flows.as_slice()[0].name.as_str(), "flow");
             assert!(spec.baseline.as_function().is_none());
@@ -297,7 +281,7 @@ mod tests {
     fn rejects_empty_or_unnamed_viewports() {
         assert_message(
             &format!("viewports = {{}}, {SERVER}, {FLOWS}"),
-            "must not be empty",
+            "viewports must not be empty",
         );
         assert_message(
             &format!(r#"viewports = {{{{"desktop", 0, 900}}}}, {SERVER}, {FLOWS}"#),
@@ -313,7 +297,7 @@ mod tests {
     fn rejects_an_empty_server_cmd() {
         assert_message(
             &format!("{VIEWPORTS}, server = {{cmd = {{}}}}, {FLOWS}"),
-            "must not be empty",
+            "server.cmd must not be empty",
         );
     }