work
[pspp] / rust / src / cooked.rs
index 0012a51dcc3dc0f1c412c6dd30556e7681ce6f9d..4b12e8f314cab6bb4c6fd6b94c55fe1deb413b6b 100644 (file)
@@ -4,9 +4,9 @@ use chrono::{NaiveDate, NaiveDateTime, NaiveTime};
 use encoding_rs::Encoding;
 
 use crate::{
-    format::Spec,
-    identifier::{Identifier, Error as IdError},
-    {endian::Endian, CategoryLabels, Compression},
+    format::{Spec, UncheckedSpec, Width},
+    identifier::{Error as IdError, Identifier},
+    {endian::Endian, CategoryLabels, Compression}, raw,
 };
 use thiserror::Error as ThisError;
 
@@ -40,14 +40,15 @@ pub struct Decoder {
 }
 
 impl Decoder {
-    fn take_name(&mut self, id: Identifier) -> bool {
-        self.var_names.insert(id)
+    fn take_name(&mut self, id: &Identifier) -> bool {
+        self.var_names.insert(id.clone())
     }
     fn generate_name(&mut self) -> Identifier {
         loop {
             self.n_generated_names += 1;
-            let name = Identifier::new(&format!("VAR{:03}", self.n_generated_names), self.encoding).unwrap();
-            if self.take_name(name.clone()) {
+            let name = Identifier::new(&format!("VAR{:03}", self.n_generated_names), self.encoding)
+                .unwrap();
+            if self.take_name(&name) {
                 return name;
             }
             assert!(self.n_generated_names < usize::MAX);
@@ -80,16 +81,16 @@ impl Decode for Header {
     type Input = crate::raw::Header;
 
     fn decode(decoder: &Decoder, input: &Self::Input, warn: impl Fn(Error)) -> Result<Self, Error> {
-        let eye_catcher = decoder.decode_string(&input.eye_catcher, &warn);
-        let file_label = decoder.decode_string(&input.file_label, &warn);
-        let creation_date = decoder.decode_string(&input.creation_date, &warn);
+        let eye_catcher = decoder.decode_string(&input.eye_catcher.0, &warn);
+        let file_label = decoder.decode_string(&input.file_label.0, &warn);
+        let creation_date = decoder.decode_string(&input.creation_date.0, &warn);
         let creation_date = NaiveDate::parse_from_str(&creation_date, "%v").unwrap_or_else(|_| {
             warn(Error::InvalidCreationDate {
                 creation_date: creation_date.into(),
             });
             Default::default()
         });
-        let creation_time = decoder.decode_string(&input.creation_time, &warn);
+        let creation_time = decoder.decode_string(&input.creation_time.0, &warn);
         let creation_time =
             NaiveTime::parse_from_str(&creation_time, "%H:%M:%S").unwrap_or_else(|_| {
                 warn(Error::InvalidCreationTime {
@@ -108,10 +109,22 @@ impl Decode for Header {
 }
 
 pub struct Variable {
-    pub width: i32,
+    pub width: Width,
     pub name: Identifier,
     pub print_format: Spec,
     pub write_format: Spec,
+    //pub missing_values: MissingValues,
+    pub label: Option<String>,
+}
+
+fn decode_format(raw: raw::Spec, name: &str, width: Width) -> Spec {
+    UncheckedSpec::try_from(raw)
+        .and_then(Spec::try_from)
+        .and_then(|x| x.check_width_compatibility(Some(name), width))
+        .unwrap_or_else(|_warning| {
+            /*warn(warning);*/
+            Spec::default_for_width(width)
+        })
 }
 
 fn decode_var(
@@ -129,10 +142,11 @@ fn decode_var(
             })
         }
     };
-    let name = decoder.decode_string(&input.name, &warn);
+    let width = input.width as Width;
+    let name = decoder.decode_string(&input.name.0, &warn);
     let name = match Identifier::new(&name, decoder.encoding) {
         Ok(name) => {
-            if !decoder.take_name(name) {
+            if !decoder.take_name(&name) {
                 decoder.generate_name()
             } else {
                 name
@@ -143,6 +157,10 @@ fn decode_var(
             decoder.generate_name()
         }
     };
+    let print_format = decode_format(input.print_format, &name.0, width);
+    let write_format = decode_format(input.write_format, &name.0, width);
+    let label = input.label.as_ref().map(|label| decoder.decode_string(&label.0, &warn).into());
+    Ok(Some(Variable { width, name, print_format, write_format, label }))
 }
 
 #[derive(Clone)]
@@ -156,7 +174,7 @@ impl Decode for Document {
             input
                 .lines
                 .iter()
-                .map(|s| decoder.decode_string(s, &warn).into())
+                .map(|s| decoder.decode_string(&s.0, &warn).into())
                 .collect(),
         ))
     }