compiles
authorBen Pfaff <blp@cs.stanford.edu>
Sat, 30 Dec 2023 19:16:29 +0000 (11:16 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Sat, 30 Dec 2023 19:16:29 +0000 (11:16 -0800)
rust/src/cooked.rs
rust/src/raw.rs

index b7802e91cd1e58526b059e416782e59101867508..3e4677e71c1bbbe80191617e92f8e935ece67fe4 100644 (file)
@@ -8,7 +8,7 @@ use crate::{
     endian::Endian,
     format::{Error as FormatError, Spec, UncheckedSpec},
     identifier::{Error as IdError, Identifier},
-    raw::{self, RawDocumentLine, RawStr, RawString, VarDisplayRecord, VarType, ProductInfoRecord},
+    raw::{self, ProductInfoRecord, RawDocumentLine, RawStr, RawString, VarDisplayRecord, VarType},
 };
 use chrono::{NaiveDate, NaiveDateTime, NaiveTime};
 use encoding_rs::{DecoderResult, Encoding};
@@ -214,7 +214,7 @@ struct Headers<'a> {
     float_info: Option<&'a raw::FloatInfoRecord>,
     variable_sets: Vec<&'a raw::VariableSetRecord>,
     var_display: Option<&'a raw::VarDisplayRecord>,
-    multiple_response: Vec<&'a raw::MultipleResponseRecord<RawString>>,
+    multiple_response: Vec<&'a raw::MultipleResponseRecord<RawString, RawString>>,
     long_string_value_labels: Vec<&'a raw::LongStringValueLabelRecord<RawString>>,
     long_string_missing_values: Vec<&'a raw::LongStringMissingValueRecord<RawString, RawStr<8>>>,
     encoding: Option<&'a raw::EncodingRecord>,
@@ -271,7 +271,6 @@ impl<'a> Headers<'a> {
                 raw::Record::ZTrailer(_) => (),
                 raw::Record::Cases(record) => set_or_warn(&mut h.cases, record, warn),
                 raw::Record::Text(_) => todo!(),
-                
             }
         }
         h
@@ -339,82 +338,82 @@ pub fn decode(
     if let Some(raw) = h.number_of_cases {
         output.push(Record::NumberOfCases(raw.clone()))
     }
-/*
-    for &raw in &h.file_attributes {
-        let s = decoder.decode_string_cow(&raw.text.0, warn);
-        output.push(Record::FileAttributes(FileAttributeRecord::parse(
-            &decoder, &s, warn,
-        )?));
-    }
-    for &raw in &h.other_extensions {
-        output.push(Record::OtherExtension(raw.clone()));
-    }
-    // Decode the variable records, which are the basis of almost everything
-    // else.
-    for &raw in &h.variables {
-        if let Some(variable) = VariableRecord::try_decode(&mut decoder, raw, warn)? {
-            output.push(Record::Variable(variable));
+    /*
+        for &raw in &h.file_attributes {
+            let s = decoder.decode_string_cow(&raw.text.0, warn);
+            output.push(Record::FileAttributes(FileAttributeRecord::parse(
+                &decoder, &s, warn,
+            )?));
+        }
+        for &raw in &h.other_extensions {
+            output.push(Record::OtherExtension(raw.clone()));
+        }
+        // Decode the variable records, which are the basis of almost everything
+        // else.
+        for &raw in &h.variables {
+            if let Some(variable) = VariableRecord::try_decode(&mut decoder, raw, warn)? {
+                output.push(Record::Variable(variable));
+            }
         }
-    }
 
-    // Decode value labels and weight variable.  These use indexes into the
-    // variable records, so we need to parse them before those indexes become
-    // invalidated by very long string variables.
-    for &raw in &h.value_labels {
-        if let Some(value_label) = ValueLabelRecord::try_decode(&mut decoder, raw, warn)? {
-            output.push(Record::ValueLabel(value_label));
+        // Decode value labels and weight variable.  These use indexes into the
+        // variable records, so we need to parse them before those indexes become
+        // invalidated by very long string variables.
+        for &raw in &h.value_labels {
+            if let Some(value_label) = ValueLabelRecord::try_decode(&mut decoder, raw, warn)? {
+                output.push(Record::ValueLabel(value_label));
+            }
+        }
+        // XXX weight
+        if let Some(raw) = h.var_display {
+            output.push(Record::VarDisplay(raw.clone()));
         }
-    }
-    // XXX weight
-    if let Some(raw) = h.var_display {
-        output.push(Record::VarDisplay(raw.clone()));
-    }
 
-    // Decode records that use short names.
-        for &raw in &h.multiple_response {
-            if let Some(mrr) = MultipleResponseRecord::try_decode(&mut decoder, raw, warn)? {
-                output.push(Record::MultipleResponse(mrr))
+        // Decode records that use short names.
+            for &raw in &h.multiple_response {
+                if let Some(mrr) = MultipleResponseRecord::try_decode(&mut decoder, raw, warn)? {
+                    output.push(Record::MultipleResponse(mrr))
+                }
             }
+        for &raw in &h.very_long_strings {
+            let s = decoder.decode_string_cow(&raw.text.0, warn);
+            output.push(Record::VeryLongStrings(VeryLongStringRecord::parse(
+                &decoder, &s, warn,
+            )?));
         }
-    for &raw in &h.very_long_strings {
-        let s = decoder.decode_string_cow(&raw.text.0, warn);
-        output.push(Record::VeryLongStrings(VeryLongStringRecord::parse(
-            &decoder, &s, warn,
-        )?));
-    }
 
-    // Rename variables to their long names.
-    for &raw in &h.long_names {
-        let s = decoder.decode_string_cow(&raw.text.0, warn);
-        output.push(Record::LongNames(LongNameRecord::parse(
-            &mut decoder,
-            &s,
-            warn,
-        )?));
-    }
+        // Rename variables to their long names.
+        for &raw in &h.long_names {
+            let s = decoder.decode_string_cow(&raw.text.0, warn);
+            output.push(Record::LongNames(LongNameRecord::parse(
+                &mut decoder,
+                &s,
+                warn,
+            )?));
+        }
 
-    // Decode recods that use long names.
-    for &raw in &h.variable_attributes {
-        let s = decoder.decode_string_cow(&raw.text.0, warn);
-        output.push(Record::VariableAttributes(VariableAttributeRecord::parse(
-            &decoder, &s, warn,
-        )?));
-    }
-    for &raw in &h.long_string_value_labels {
-        if let Some(mrr) = LongStringValueLabelRecord::try_decode(&mut decoder, raw, warn)? {
-            output.push(Record::LongStringValueLabels(mrr))
+        // Decode recods that use long names.
+        for &raw in &h.variable_attributes {
+            let s = decoder.decode_string_cow(&raw.text.0, warn);
+            output.push(Record::VariableAttributes(VariableAttributeRecord::parse(
+                &decoder, &s, warn,
+            )?));
         }
-    }
-    for &raw in &h.long_string_missing_values {
-        if let Some(mrr) = LongStringMissingValuesRecord::try_decode(&mut decoder, raw, warn)? {
-            output.push(Record::LongStringMissingValues(mrr))
+        for &raw in &h.long_string_value_labels {
+            if let Some(mrr) = LongStringValueLabelRecord::try_decode(&mut decoder, raw, warn)? {
+                output.push(Record::LongStringValueLabels(mrr))
+            }
         }
-    }
-    for &raw in &h.variable_sets {
-        let s = decoder.decode_string_cow(&raw.text.0, warn);
-        output.push(Record::VariableSets(VariableSetRecord::parse(&s, warn)?));
-    }
-*/
+        for &raw in &h.long_string_missing_values {
+            if let Some(mrr) = LongStringMissingValuesRecord::try_decode(&mut decoder, raw, warn)? {
+                output.push(Record::LongStringMissingValues(mrr))
+            }
+        }
+        for &raw in &h.variable_sets {
+            let s = decoder.decode_string_cow(&raw.text.0, warn);
+            output.push(Record::VariableSets(VariableSetRecord::parse(&s, warn)?));
+        }
+    */
     Ok(output)
 }
 
@@ -1218,21 +1217,12 @@ pub struct MultipleResponseSet {
 impl MultipleResponseSet {
     fn decode(
         decoder: &Decoder,
-        input: &raw::MultipleResponseSet<Cow<str>>,
+        input: &raw::MultipleResponseSet<Identifier, Cow<str>>,
         warn: &impl Fn(Error),
     ) -> Result<Self, Error> {
-        let mr_set_name =
-            Identifier::new(&input.name, decoder.encoding).map_err(Error::InvalidMrSetName)?;
-
+        let mr_set_name = input.name.clone();
         let mut dict_indexes = Vec::with_capacity(input.short_names.len());
         for short_name in input.short_names.iter() {
-            let short_name = match Identifier::new(&short_name, decoder.encoding) {
-                Ok(name) => name,
-                Err(error) => {
-                    warn(Error::InvalidMrSetName(error));
-                    continue;
-                }
-            };
             let Some(&dict_index) = decoder.var_names.get(&short_name) else {
                 warn(Error::UnknownMrSetVariable {
                     mr_set: mr_set_name.clone(),
@@ -1276,7 +1266,7 @@ impl MultipleResponseSet {
 pub struct MultipleResponseRecord(pub Vec<MultipleResponseSet>);
 
 impl TryDecode for MultipleResponseRecord {
-    type Input<'a> = raw::MultipleResponseRecord<Cow<'a, str>>;
+    type Input<'a> = raw::MultipleResponseRecord<Identifier, Cow<'a, str>>;
 
     fn try_decode(
         decoder: &mut Decoder,
index ba7124a3856c9e9f18c384aed5f5fed787242e8a..544481906f20153aabd415e50f507b198375c73f 100644 (file)
@@ -179,6 +179,12 @@ pub enum Error {
     #[error("Invalid variable name in variable set record.  {0}")]
     InvalidVariableSetName(IdError),
 
+    #[error("Invalid multiple response set name.  {0}")]
+    InvalidMrSetName(IdError),
+
+    #[error("Invalid multiple response set variable name.  {0}")]
+    InvalidMrSetVariableName(IdError),
+
     #[error("Details TBD")]
     TBD,
 }
@@ -193,7 +199,7 @@ pub enum Record {
     FloatInfo(FloatInfoRecord),
     VariableSets(VariableSetRecord),
     VarDisplay(VarDisplayRecord),
-    MultipleResponse(MultipleResponseRecord<RawString>),
+    MultipleResponse(MultipleResponseRecord<RawString, RawString>),
     LongStringValueLabels(LongStringValueLabelRecord<RawString>),
     LongStringMissingValues(LongStringMissingValueRecord<RawString, RawStr<8>>),
     Encoding(EncodingRecord),
@@ -1643,17 +1649,18 @@ impl MultipleResponseType {
 }
 
 #[derive(Clone, Debug)]
-pub struct MultipleResponseSet<S>
+pub struct MultipleResponseSet<I, S>
 where
+    I: Debug,
     S: Debug,
 {
-    pub name: S,
+    pub name: I,
     pub label: S,
     pub mr_type: MultipleResponseType,
-    pub short_names: Vec<S>,
+    pub short_names: Vec<I>,
 }
 
-impl MultipleResponseSet<RawString> {
+impl MultipleResponseSet<RawString, RawString> {
     fn parse(input: &[u8]) -> Result<(Self, &[u8]), Error> {
         let Some(equals) = input.iter().position(|&b| b == b'=') else {
             return Err(Error::TBD);
@@ -1694,22 +1701,38 @@ impl MultipleResponseSet<RawString> {
         ))
     }
 
-    fn decode<'a>(&'a self, decoder: &Decoder) -> MultipleResponseSet<Cow<'a, str>> {
-        MultipleResponseSet {
-            name: decoder.decode(&self.name),
+    fn decode<'a>(
+        &'a self,
+        decoder: &Decoder,
+    ) -> Result<MultipleResponseSet<Identifier, Cow<'a, str>>, Error> {
+        let mut short_names = Vec::with_capacity(self.short_names.len());
+        for short_name in self.short_names.iter() {
+            if let Some(short_name) = decoder
+                .decode_identifier(short_name)
+                .map_err(|err| Error::InvalidMrSetName(err))
+                .warn_on_error(&decoder.warn)
+            {
+                short_names.push(short_name);
+            }
+        }
+        Ok(MultipleResponseSet {
+            name: decoder
+                .decode_identifier(&self.name)
+                .map_err(|err| Error::InvalidMrSetVariableName(err))?,
             label: decoder.decode(&self.label),
             mr_type: self.mr_type.clone(),
-            short_names: self.short_names.iter().map(|s| decoder.decode(s)).collect(),
-        }
+            short_names: short_names,
+        })
     }
 }
 
 #[derive(Clone, Debug)]
-pub struct MultipleResponseRecord<S>(pub Vec<MultipleResponseSet<S>>)
+pub struct MultipleResponseRecord<I, S>(pub Vec<MultipleResponseSet<I, S>>)
 where
+    I: Debug,
     S: Debug;
 
-impl ExtensionRecord for MultipleResponseRecord<RawString> {
+impl ExtensionRecord for MultipleResponseRecord<RawString, RawString> {
     const SUBTYPE: u32 = 7;
     const SIZE: Option<u32> = Some(1);
     const COUNT: Option<u32> = None;
@@ -1729,9 +1752,15 @@ impl ExtensionRecord for MultipleResponseRecord<RawString> {
     }
 }
 
-impl MultipleResponseRecord<RawString> {
-    fn decode<'a>(&'a self, decoder: &Decoder) -> MultipleResponseRecord<Cow<'a, str>> {
-        MultipleResponseRecord(self.0.iter().map(|set| set.decode(decoder)).collect())
+impl MultipleResponseRecord<RawString, RawString> {
+    fn decode<'a>(&'a self, decoder: &Decoder) -> MultipleResponseRecord<Identifier, Cow<'a, str>> {
+        let mut sets = Vec::new();
+        for set in self.0.iter() {
+            if let Some(set) = set.decode(decoder).warn_on_error(&decoder.warn) {
+                sets.push(set);
+            }
+        }
+        MultipleResponseRecord(sets)
     }
 }