work on value labels
[pspp] / rust / src / cooked.rs
index ee66890027040eba699b7de61c04894279a7eaf2..71d65adddd6cfa0ddd50e458d2df9259f7140535 100644 (file)
@@ -1,4 +1,4 @@
-use std::{cell::RefCell, ops::Range, rc::Rc, collections::HashMap};
+use std::{cell::RefCell, collections::HashMap, ops::Range, rc::Rc};
 
 use crate::{
     dictionary::{Dictionary, VarWidth, Variable},
@@ -85,17 +85,23 @@ pub enum Error {
     #[error("Dictionary index {0} refers to a long string continuation.")]
     DictIndexIsContinuation(usize),
 
+    #[error("At offset {offset:#x}, one or more variable indexes for value labels referred to long string continuation records: {indexes:?}")]
+    LongStringContinuationIndexes { offset: u64, indexes: Vec<u32> },
+
+    #[error(
+        "At offsets {:#x}...{:#x}, record types 3 and 4 may not add value labels to one or more long string variables: {variables:?}", .offsets.start, .offsets.end
+    )]
+    InvalidLongStringValueLabels {
+        offsets: Range<u64>,
+        variables: Vec<Identifier>,
+    },
+
     #[error("Variables associated with value label are not all of identical type.  Variable {numeric_var} is numeric, but variable {string_var} is string.")]
     ValueLabelsDifferentTypes {
         numeric_var: Identifier,
         string_var: Identifier,
     },
 
-    #[error(
-        "Value labels may not be added to long string variable {0} using record types 3 or 4."
-    )]
-    InvalidLongStringValueLabel(Identifier),
-
     #[error("Invalid multiple response set name.  {0}")]
     InvalidMrSetName(IdError),
 
@@ -512,6 +518,36 @@ pub fn decode(
         assert_eq!(var_index_map.insert(value_index, dict_index), None);
     }
 
+    for record in headers.value_label.drain(..) {
+        let mut dict_indexes = Vec::with_capacity(record.dict_indexes.len());
+        let mut continuation_indexes = Vec::new();
+        let mut long_string_variables = Vec::new();
+        for value_index in record.dict_indexes.iter() {
+            if let Some(dict_index) = var_index_map.get(&(*value_index as usize - 1)) {
+                let variable = &dictionary.variables[*dict_index];
+                if variable.width.is_long_string() {
+                    long_string_variables.push(variable.name.clone());
+                } else {
+                    dict_indexes.push(*dict_index);
+                }
+            } else {
+                continuation_indexes.push(*value_index);
+            }
+        }
+        if !continuation_indexes.is_empty() {
+            warn(Error::LongStringContinuationIndexes {
+                offset: record.offsets.start,
+                indexes: continuation_indexes,
+            });
+        }
+        if !long_string_variables.is_empty() {
+            warn(Error::InvalidLongStringValueLabels {
+                offsets: record.offsets.clone(),
+                variables: long_string_variables,
+            });
+        }
+    }
+
     let metadata = Metadata::decode(&headers, warn);
     Ok((dictionary, metadata))
 }