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};
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>,
raw::Record::ZTrailer(_) => (),
raw::Record::Cases(record) => set_or_warn(&mut h.cases, record, warn),
raw::Record::Text(_) => todo!(),
-
}
}
h
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)
}
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(),
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,
#[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,
}
FloatInfo(FloatInfoRecord),
VariableSets(VariableSetRecord),
VarDisplay(VarDisplayRecord),
- MultipleResponse(MultipleResponseRecord<RawString>),
+ MultipleResponse(MultipleResponseRecord<RawString, RawString>),
LongStringValueLabels(LongStringValueLabelRecord<RawString>),
LongStringMissingValues(LongStringMissingValueRecord<RawString, RawStr<8>>),
Encoding(EncodingRecord),
}
#[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);
))
}
- 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;
}
}
-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)
}
}