cleanup
[pspp] / rust / src / format.rs
index 857c05e67f16490ea4dc7b7ac55ee3e21816469a..9f285a9dd6710624564f90fea197b56307bad82c 100644 (file)
@@ -5,11 +5,14 @@ use std::{
 
 use thiserror::Error as ThisError;
 
-use crate::raw::{VarType, self};
+use crate::{
+    cooked::VarWidth,
+    raw::{self, VarType},
+};
 
 #[derive(ThisError, Debug)]
 pub enum Error {
-    #[error("Unknown format type {value}")]
+    #[error("Unknown format type {value}.")]
     UnknownFormat { value: u16 },
 
     #[error("Output format {0} specifies width {}, but {} requires an even width.", .0.w, .0.format)]
@@ -36,12 +39,6 @@ pub enum Error {
     #[error("Numeric variable is not compatible with string format {0}.")]
     UnnamedVariableNotCompatibleWithStringFormat(Format),
 
-    #[error("String variable {variable} is not compatible with numeric format {format}.")]
-    NamedVariableNotCompatibleWithNumericFormat { variable: String, format: Format },
-
-    #[error("Numeric variable {variable} is not compatible with string format {format}.")]
-    NamedVariableNotCompatibleWithStringFormat { variable: String, format: Format },
-
     #[error("String variable {variable} with width {width} is not compatible with format {bad_spec}.  Use format {good_spec} instead.")]
     NamedStringVariableBadSpecWidth {
         variable: String,
@@ -173,8 +170,6 @@ pub enum Format {
     AHex,
 }
 
-pub const MAX_STRING: Width = 32767;
-
 pub type Width = u16;
 pub type SignedWidth = i16;
 
@@ -185,8 +180,8 @@ impl Format {
         match self {
             Self::P | Self::PK | Self::PIBHex | Self::RBHex => 16,
             Self::IB | Self::PIB | Self::RB => 8,
-            Self::A => MAX_STRING,
-            Self::AHex => MAX_STRING * 2,
+            Self::A => 32767,
+            Self::AHex => 32767 * 2,
             _ => 40,
         }
     }
@@ -305,36 +300,20 @@ impl Format {
     pub fn var_type(self) -> VarType {
         match self {
             Self::A | Self::AHex => VarType::String,
-            _ => VarType::Number,
+            _ => VarType::Numeric,
         }
     }
 
-    pub fn check_type_compatibility(
-        self,
-        variable: Option<&str>,
-        var_type: VarType,
-    ) -> Result<(), Error> {
+    /// Checks whether this format is valid for a variable with the given
+    /// `var_type`.
+    pub fn check_type_compatibility(self, var_type: VarType) -> Result<(), Error> {
         let my_type = self.var_type();
         match (my_type, var_type) {
-            (VarType::Number, VarType::String) => {
-                if let Some(variable) = variable {
-                    Err(Error::NamedVariableNotCompatibleWithNumericFormat {
-                        variable: variable.into(),
-                        format: self,
-                    })
-                } else {
-                    Err(Error::UnnamedVariableNotCompatibleWithNumericFormat(self))
-                }
+            (VarType::Numeric, VarType::String) => {
+                Err(Error::UnnamedVariableNotCompatibleWithNumericFormat(self))
             }
-            (VarType::String, VarType::Number) => {
-                if let Some(variable) = variable {
-                    Err(Error::NamedVariableNotCompatibleWithStringFormat {
-                        variable: variable.into(),
-                        format: self,
-                    })
-                } else {
-                    Err(Error::UnnamedVariableNotCompatibleWithStringFormat(self))
-                }
+            (VarType::String, VarType::Numeric) => {
+                Err(Error::UnnamedVariableNotCompatibleWithStringFormat(self))
             }
             _ => Ok(()),
         }
@@ -404,10 +383,18 @@ impl Spec {
         self.d
     }
 
-    pub fn default_for_width(w: Width) -> Self {
-        match w {
-            0 => Spec { format: Format::F, w: 8, d: 2 },
-            _ => Spec { format: Format::A, w: w, d: 0 },
+    pub fn default_for_width(var_width: VarWidth) -> Self {
+        match var_width {
+            VarWidth::Numeric => Spec {
+                format: Format::F,
+                w: 8,
+                d: 2,
+            },
+            VarWidth::String(w) => Spec {
+                format: Format::A,
+                w,
+                d: 0,
+            },
         }
     }
 
@@ -425,11 +412,11 @@ impl Spec {
         Self { format, w, d }
     }
 
-    pub fn var_width(self) -> Width {
+    pub fn var_width(self) -> VarWidth {
         match self.format {
-            Format::A => self.w,
-            Format::AHex => self.w / 2,
-            _ => 0,
+            Format::A => VarWidth::String(self.w),
+            Format::AHex => VarWidth::String(self.w / 2),
+            _ => VarWidth::Numeric,
         }
     }
 
@@ -437,33 +424,29 @@ impl Spec {
         self.format.var_type()
     }
 
-    pub fn check_width_compatibility(self, variable: Option<&str>, w: Width) -> Result<Self, Error> {
-        self.format.check_type_compatibility(variable, self.var_type())?;
-        let expected_width = self.var_width();
-        if w != expected_width {
-            let bad_spec = self;
-            let good_spec = if self.format == Format::A {
-                Spec { w, ..self }
-            } else {
-                Spec { w: w * 2, ..self }
-            };
-            if let Some(variable) = variable {
-                Err(Error::NamedStringVariableBadSpecWidth {
-                    variable: variable.into(),
-                    width: w,
-                    bad_spec,
-                    good_spec,
-                })
-            } else {
-                Err(Error::UnnamedStringVariableBadSpecWidth {
+    /// Checks whether this format specification is valid for a variable with
+    /// width `var_width`.
+    pub fn check_width_compatibility(self, var_width: VarWidth) -> Result<Self, Error> {
+        // Verify that the format is right for the variable's type.
+        self.format.check_type_compatibility(var_width.into())?;
+
+        if let VarWidth::String(w) = var_width {
+            if var_width != self.var_width() {
+                let bad_spec = self;
+                let good_spec = if self.format == Format::A {
+                    Spec { w, ..self }
+                } else {
+                    Spec { w: w * 2, ..self }
+                };
+                return Err(Error::UnnamedStringVariableBadSpecWidth {
                     width: w,
                     bad_spec,
                     good_spec,
-                })
+                });
             }
-        } else {
-            Ok(self)
         }
+
+        Ok(self)
     }
 }