documentrecord
[pspp] / rust / src / cooked.rs
1 use std::{
2     borrow::Cow, cell::RefCell, cmp::Ordering, collections::HashMap, iter::repeat, ops::Range,
3     rc::Rc,
4 };
5
6 use crate::{
7     encoding::{default_encoding, get_encoding, Error as EncodingError},
8     endian::Endian,
9     format::{Error as FormatError, Spec, UncheckedSpec},
10     identifier::{Error as IdError, Identifier},
11     raw::{self, RawStr, RawString, VarType, RawDocumentLine},
12 };
13 use chrono::{NaiveDate, NaiveDateTime, NaiveTime};
14 use encoding_rs::{DecoderResult, Encoding};
15 use num::integer::div_ceil;
16 use ordered_float::OrderedFloat;
17 use thiserror::Error as ThisError;
18
19 pub use crate::raw::{CategoryLabels, Compression};
20
21 #[derive(ThisError, Debug)]
22 pub enum Error {
23     // XXX this is really an internal error and maybe we should change the
24     // interfaces to make it impossible
25     #[error("Missing header record")]
26     MissingHeaderRecord,
27
28     #[error("{0}")]
29     EncodingError(EncodingError),
30
31     #[error("Using default encoding {0}.")]
32     UsingDefaultEncoding(String),
33
34     #[error("Variable record from offset {:x} to {:x} specifies width {width} not in valid range [-1,255).", offsets.start, offsets.end)]
35     InvalidVariableWidth { offsets: Range<u64>, width: i32 },
36
37     #[error("This file has corrupted metadata written by a buggy version of PSPP.  To ensure that other software can read it correctly, save a new copy of the file.")]
38     InvalidLongMissingValueFormat,
39
40     #[error("File creation date {creation_date} is not in the expected format \"DD MMM YY\" format.  Using 01 Jan 1970.")]
41     InvalidCreationDate { creation_date: String },
42
43     #[error("File creation time {creation_time} is not in the expected format \"HH:MM:SS\" format.  Using midnight.")]
44     InvalidCreationTime { creation_time: String },
45
46     #[error("{id_error}  Renaming variable to {new_name}.")]
47     InvalidVariableName {
48         id_error: IdError,
49         new_name: Identifier,
50     },
51
52     #[error(
53         "Substituting {new_spec} for invalid print format on variable {variable}.  {format_error}"
54     )]
55     InvalidPrintFormat {
56         new_spec: Spec,
57         variable: Identifier,
58         format_error: FormatError,
59     },
60
61     #[error(
62         "Substituting {new_spec} for invalid write format on variable {variable}.  {format_error}"
63     )]
64     InvalidWriteFormat {
65         new_spec: Spec,
66         variable: Identifier,
67         format_error: FormatError,
68     },
69
70     #[error("Renaming variable with duplicate name {duplicate_name} to {new_name}.")]
71     DuplicateVariableName {
72         duplicate_name: Identifier,
73         new_name: Identifier,
74     },
75
76     #[error("Dictionary index {dict_index} is outside valid range [1,{max_index}].")]
77     InvalidDictIndex { dict_index: usize, max_index: usize },
78
79     #[error("Dictionary index {0} refers to a long string continuation.")]
80     DictIndexIsContinuation(usize),
81
82     #[error("Variables associated with value label are not all of identical type.  Variable {numeric_var} is numeric, but variable {string_var} is string.")]
83     ValueLabelsDifferentTypes {
84         numeric_var: Identifier,
85         string_var: Identifier,
86     },
87
88     #[error(
89         "Value labels may not be added to long string variable {0} using record types 3 or 4."
90     )]
91     InvalidLongStringValueLabel(Identifier),
92
93     #[error("Invalid multiple response set name.  {0}")]
94     InvalidMrSetName(IdError),
95
96     #[error("Multiple response set {mr_set} includes unknown variable {short_name}.")]
97     UnknownMrSetVariable {
98         mr_set: Identifier,
99         short_name: Identifier,
100     },
101
102     #[error("Multiple response set {0} has no variables.")]
103     EmptyMrSet(Identifier),
104
105     #[error("Multiple response set {0} has only one variable.")]
106     OneVarMrSet(Identifier),
107
108     #[error("Multiple response set {0} contains both string and numeric variables.")]
109     MixedMrSet(Identifier),
110
111     #[error(
112         "Invalid numeric format for counted value {number} in multiple response set {mr_set}."
113     )]
114     InvalidMDGroupCountedValue { mr_set: Identifier, number: String },
115
116     #[error("Counted value {value} has width {width}, but it must be no wider than {max_width}, the width of the narrowest variable in multiple response set {mr_set}.")]
117     TooWideMDGroupCountedValue {
118         mr_set: Identifier,
119         value: String,
120         width: usize,
121         max_width: u16,
122     },
123
124     #[error("Long string value label for variable {name} has width {width}, which is not in the valid range [{min_width},{max_width}].")]
125     InvalidLongValueLabelWidth {
126         name: Identifier,
127         width: u32,
128         min_width: u16,
129         max_width: u16,
130     },
131
132     #[error("Invalid attribute name.  {0}")]
133     InvalidAttributeName(IdError),
134
135     #[error("Invalid short name in long variable name record.  {0}")]
136     InvalidShortName(IdError),
137
138     #[error("Invalid name in long variable name record.  {0}")]
139     InvalidLongName(IdError),
140
141     #[error("Invalid variable name in very long string record.  {0}")]
142     InvalidLongStringName(IdError),
143
144     #[error("Invalid variable name in long string value label record.  {0}")]
145     InvalidLongStringValueLabelName(IdError),
146
147     #[error("Invalid variable name in attribute record.  {0}")]
148     InvalidAttributeVariableName(IdError),
149
150     // XXX This is risky because `text` might be arbitarily long.
151     #[error("Text string contains invalid bytes for {encoding} encoding: {text}")]
152     MalformedString { encoding: String, text: String },
153
154     #[error("Invalid variable measurement level value {0}")]
155     InvalidMeasurement(u32),
156
157     #[error("Invalid variable display alignment value {0}")]
158     InvalidAlignment(u32),
159
160     #[error("Details TBD")]
161     TBD,
162 }
163
164 #[derive(Clone, Debug)]
165 pub enum Record {
166     Header(HeaderRecord),
167     Variable(VariableRecord),
168     ValueLabel(ValueLabelRecord),
169     Document(DocumentRecord),
170     IntegerInfo(IntegerInfoRecord),
171     FloatInfo(FloatInfoRecord),
172     VariableSets(VariableSetRecord),
173     VarDisplay(VarDisplayRecord),
174     MultipleResponse(MultipleResponseRecord),
175     LongStringMissingValues(LongStringMissingValuesRecord),
176     LongStringValueLabels(LongStringValueLabelRecord),
177     Encoding(EncodingRecord),
178     NumberOfCases(NumberOfCasesRecord),
179     ProductInfo(ProductInfoRecord),
180     LongNames(LongNameRecord),
181     VeryLongStrings(VeryLongStringRecord),
182     FileAttributes(FileAttributeRecord),
183     VariableAttributes(VariableAttributeRecord),
184     OtherExtension(Extension),
185     //Case(Vec<Value>),
186 }
187
188 pub use crate::raw::EncodingRecord;
189 pub use crate::raw::Extension;
190 pub use crate::raw::FloatInfoRecord;
191 pub use crate::raw::IntegerInfoRecord;
192 pub use crate::raw::NumberOfCasesRecord;
193
194 type DictIndex = usize;
195
196 pub struct Variable {
197     pub dict_index: DictIndex,
198     pub short_name: Identifier,
199     pub long_name: Option<Identifier>,
200     pub width: VarWidth,
201 }
202
203 pub struct Decoder {
204     pub compression: Option<Compression>,
205     pub endian: Endian,
206     pub encoding: &'static Encoding,
207     pub variables: HashMap<DictIndex, Variable>,
208     pub var_names: HashMap<Identifier, DictIndex>,
209     n_dict_indexes: usize,
210     n_generated_names: usize,
211 }
212
213 #[derive(Default)]
214 struct Headers<'a> {
215     header: Option<&'a raw::HeaderRecord<RawString>>,
216     variables: Vec<&'a raw::VariableRecord<RawString, RawStr<8>>>,
217     value_labels: Vec<&'a raw::ValueLabelRecord<RawStr<8>, RawString>>,
218     document: Option<&'a raw::DocumentRecord<RawDocumentLine>>,
219     integer_info: Option<&'a raw::IntegerInfoRecord>,
220     float_info: Option<&'a raw::FloatInfoRecord>,
221     variable_sets: Vec<&'a raw::TextRecord>,
222     var_display: Option<&'a raw::VarDisplayRecord>,
223     multiple_response: Vec<&'a raw::MultipleResponseRecord>,
224     long_string_value_labels: Vec<&'a raw::LongStringValueLabelRecord>,
225     long_string_missing_values: Vec<&'a raw::LongStringMissingValueRecord>,
226     encoding: Option<&'a raw::EncodingRecord>,
227     number_of_cases: Option<&'a raw::NumberOfCasesRecord>,
228     product_info: Option<&'a raw::TextRecord>,
229     long_names: Option<&'a raw::TextRecord>,
230     very_long_strings: Vec<&'a raw::TextRecord>,
231     file_attributes: Vec<&'a raw::TextRecord>,
232     variable_attributes: Vec<&'a raw::TextRecord>,
233     other_extensions: Vec<&'a raw::Extension>,
234     cases: Option<&'a Rc<RefCell<raw::Cases>>>,
235 }
236
237 fn set_or_warn<T>(option: &mut Option<T>, value: T, warn: &impl Fn(Error)) {
238     if option.is_none() {
239         let _ = option.insert(value);
240     } else {
241         warn(Error::TBD);
242     }
243 }
244
245 impl<'a> Headers<'a> {
246     fn new(headers: &'a Vec<raw::Record>, warn: &impl Fn(Error)) -> Headers<'a> {
247         let mut h = Headers::default();
248         for header in headers {
249             match header {
250                 raw::Record::Header(record) => set_or_warn(&mut h.header, record, warn),
251                 raw::Record::Variable(record) => h.variables.push(record),
252                 raw::Record::ValueLabel(record) => h.value_labels.push(record),
253                 raw::Record::Document(record) => set_or_warn(&mut h.document, record, warn),
254                 raw::Record::IntegerInfo(record) => set_or_warn(&mut h.integer_info, record, warn),
255                 raw::Record::FloatInfo(record) => set_or_warn(&mut h.float_info, record, warn),
256                 raw::Record::VariableSets(record) => h.variable_sets.push(record),
257                 raw::Record::VarDisplay(record) => set_or_warn(&mut h.var_display, record, warn),
258                 raw::Record::MultipleResponse(record) => h.multiple_response.push(record),
259                 raw::Record::LongStringValueLabels(record) => {
260                     h.long_string_value_labels.push(record)
261                 }
262                 raw::Record::LongStringMissingValues(record) => {
263                     h.long_string_missing_values.push(record)
264                 }
265                 raw::Record::Encoding(record) => set_or_warn(&mut h.encoding, record, warn),
266                 raw::Record::NumberOfCases(record) => {
267                     set_or_warn(&mut h.number_of_cases, record, warn)
268                 }
269                 raw::Record::ProductInfo(record) => set_or_warn(&mut h.product_info, record, warn),
270                 raw::Record::LongNames(record) => set_or_warn(&mut h.long_names, record, warn),
271                 raw::Record::VeryLongStrings(record) => h.very_long_strings.push(record),
272                 raw::Record::FileAttributes(record) => h.file_attributes.push(record),
273                 raw::Record::VariableAttributes(record) => h.variable_attributes.push(record),
274                 raw::Record::OtherExtension(record) => h.other_extensions.push(record),
275                 raw::Record::EndOfHeaders(_) => (),
276                 raw::Record::ZHeader(_) => (),
277                 raw::Record::ZTrailer(_) => (),
278                 raw::Record::Cases(record) => set_or_warn(&mut h.cases, record, warn),
279             }
280         }
281         h
282     }
283 }
284
285 pub fn decode(
286     headers: Vec<raw::Record>,
287     encoding: Option<&'static Encoding>,
288     warn: &impl Fn(Error),
289 ) -> Result<Vec<Record>, Error> {
290     let h = Headers::new(&headers, warn);
291     let Some(header) = h.header else {
292         return Err(Error::MissingHeaderRecord);
293     };
294     let encoding = match encoding {
295         Some(encoding) => encoding,
296         None => {
297             let encoding = h.encoding.map(|record| record.0.as_str());
298             let character_code = h.integer_info.map(|record| record.character_code);
299             match get_encoding(encoding, character_code) {
300                 Ok(encoding) => encoding,
301                 Err(err @ EncodingError::Ebcdic) => return Err(Error::EncodingError(err)),
302                 Err(err) => {
303                     warn(Error::EncodingError(err));
304                     // Warn that we're using the default encoding.
305                     default_encoding()
306                 }
307             }
308         }
309     };
310
311     //let mut dictionary = Dictionary::new(encoding);
312
313     let mut decoder = Decoder {
314         compression: header.compression,
315         endian: header.endian,
316         encoding,
317         variables: HashMap::new(),
318         var_names: HashMap::new(),
319         n_dict_indexes: 0,
320         n_generated_names: 0,
321     };
322
323     let mut output = Vec::with_capacity(headers.len());
324
325     // Decode the records that don't use variables at all.
326     if let Some(header) = HeaderRecord::try_decode(&mut decoder, header, warn)? {
327         output.push(Record::Header(header))
328     }
329     if let Some(raw) = h.document {
330         if let Some(document) = DocumentRecord::try_decode(&mut decoder, raw, warn)? {
331             output.push(Record::Document(document))
332         }
333     }
334     if let Some(raw) = h.integer_info {
335         output.push(Record::IntegerInfo(raw.clone()));
336     }
337     if let Some(raw) = h.float_info {
338         output.push(Record::FloatInfo(raw.clone()));
339     }
340     if let Some(raw) = h.product_info {
341         let s = decoder.decode_string_cow(&raw.text.0, warn);
342         output.push(Record::ProductInfo(ProductInfoRecord::parse(&s, warn)?));
343     }
344     if let Some(raw) = h.number_of_cases {
345         output.push(Record::NumberOfCases(raw.clone()))
346     }
347     for &raw in &h.file_attributes {
348         let s = decoder.decode_string_cow(&raw.text.0, warn);
349         output.push(Record::FileAttributes(FileAttributeRecord::parse(
350             &decoder, &s, warn,
351         )?));
352     }
353     for &raw in &h.other_extensions {
354         output.push(Record::OtherExtension(raw.clone()));
355     }
356
357     // Decode the variable records, which are the basis of almost everything
358     // else.
359     for &raw in &h.variables {
360         if let Some(variable) = VariableRecord::try_decode(&mut decoder, raw, warn)? {
361             output.push(Record::Variable(variable));
362         }
363     }
364
365     // Decode value labels and weight variable.  These use indexes into the
366     // variable records, so we need to parse them before those indexes become
367     // invalidated by very long string variables.
368     for &raw in &h.value_labels {
369         if let Some(value_label) = ValueLabelRecord::try_decode(&mut decoder, raw, warn)? {
370             output.push(Record::ValueLabel(value_label));
371         }
372     }
373     // XXX weight
374     if let Some(raw) = h.var_display {
375         if let Some(vdr) = VarDisplayRecord::try_decode(&mut decoder, raw, warn)? {
376             output.push(Record::VarDisplay(vdr))
377         }
378     }
379
380     // Decode records that use short names.
381     for &raw in &h.multiple_response {
382         if let Some(mrr) = MultipleResponseRecord::try_decode(&mut decoder, raw, warn)? {
383             output.push(Record::MultipleResponse(mrr))
384         }
385     }
386     for &raw in &h.very_long_strings {
387         let s = decoder.decode_string_cow(&raw.text.0, warn);
388         output.push(Record::VeryLongStrings(VeryLongStringRecord::parse(
389             &decoder, &s, warn,
390         )?));
391     }
392
393     // Rename variables to their long names.
394     for &raw in &h.long_names {
395         let s = decoder.decode_string_cow(&raw.text.0, warn);
396         output.push(Record::LongNames(LongNameRecord::parse(
397             &mut decoder,
398             &s,
399             warn,
400         )?));
401     }
402
403     // Decode recods that use long names.
404     for &raw in &h.variable_attributes {
405         let s = decoder.decode_string_cow(&raw.text.0, warn);
406         output.push(Record::VariableAttributes(VariableAttributeRecord::parse(
407             &decoder, &s, warn,
408         )?));
409     }
410     for &raw in &h.long_string_value_labels {
411         if let Some(mrr) = LongStringValueLabelRecord::try_decode(&mut decoder, raw, warn)? {
412             output.push(Record::LongStringValueLabels(mrr))
413         }
414     }
415     for &raw in &h.long_string_missing_values {
416         if let Some(mrr) = LongStringMissingValuesRecord::try_decode(&mut decoder, raw, warn)? {
417             output.push(Record::LongStringMissingValues(mrr))
418         }
419     }
420     for &raw in &h.variable_sets {
421         let s = decoder.decode_string_cow(&raw.text.0, warn);
422         output.push(Record::VariableSets(VariableSetRecord::parse(&s, warn)?));
423     }
424     Ok(output)
425 }
426
427 impl Decoder {
428     fn generate_name(&mut self) -> Identifier {
429         loop {
430             self.n_generated_names += 1;
431             let name = Identifier::new(&format!("VAR{:03}", self.n_generated_names), self.encoding)
432                 .unwrap();
433             if !self.var_names.contains_key(&name) {
434                 return name;
435             }
436             assert!(self.n_generated_names < usize::MAX);
437         }
438     }
439     fn decode_string_cow<'a>(&self, input: &'a [u8], warn: &impl Fn(Error)) -> Cow<'a, str> {
440         let (output, malformed) = self.encoding.decode_without_bom_handling(input);
441         if malformed {
442             warn(Error::MalformedString {
443                 encoding: self.encoding.name().into(),
444                 text: output.clone().into(),
445             });
446         }
447         output
448     }
449     fn decode_string(&self, input: &[u8], warn: &impl Fn(Error)) -> String {
450         self.decode_string_cow(input, warn).into()
451     }
452     pub fn decode_identifier(
453         &self,
454         input: &[u8],
455         warn: &impl Fn(Error),
456     ) -> Result<Identifier, IdError> {
457         let s = self.decode_string_cow(input, warn);
458         Identifier::new(&s, self.encoding)
459     }
460     fn get_var_by_index(&self, dict_index: usize) -> Result<&Variable, Error> {
461         let max_index = self.n_dict_indexes;
462         if dict_index == 0 || dict_index > max_index {
463             return Err(Error::InvalidDictIndex {
464                 dict_index,
465                 max_index,
466             });
467         }
468         let Some(variable) = self.variables.get(&(dict_index - 1)) else {
469             return Err(Error::DictIndexIsContinuation(dict_index));
470         };
471         Ok(variable)
472     }
473
474     /// Returns `input` decoded from `self.encoding` into UTF-8 such that
475     /// re-encoding the result back into `self.encoding` will have exactly the
476     /// same length in bytes.
477     ///
478     /// XXX warn about errors?
479     fn decode_exact_length<'a>(&self, input: &'a [u8]) -> Cow<'a, str> {
480         if let (s, false) = self.encoding.decode_without_bom_handling(input) {
481             // This is the common case.  Usually there will be no errors.
482             s
483         } else {
484             // Unusual case.  Don't bother to optimize it much.
485             let mut decoder = self.encoding.new_decoder_without_bom_handling();
486             let mut output = String::with_capacity(
487                 decoder
488                     .max_utf8_buffer_length_without_replacement(input.len())
489                     .unwrap(),
490             );
491             let mut rest = input;
492             while !rest.is_empty() {
493                 match decoder.decode_to_string_without_replacement(rest, &mut output, true) {
494                     (DecoderResult::InputEmpty, _) => break,
495                     (DecoderResult::OutputFull, _) => unreachable!(),
496                     (DecoderResult::Malformed(a, b), consumed) => {
497                         let skipped = a as usize + b as usize;
498                         output.extend(repeat('?').take(skipped));
499                         rest = &rest[consumed..];
500                     }
501                 }
502             }
503             assert_eq!(self.encoding.encode(&output).0.len(), input.len());
504             output.into()
505         }
506     }
507 }
508
509 pub trait TryDecode: Sized {
510     type Input;
511     fn try_decode(
512         decoder: &mut Decoder,
513         input: &Self::Input,
514         warn: impl Fn(Error),
515     ) -> Result<Option<Self>, Error>;
516 }
517
518 pub trait Decode<Input>: Sized {
519     fn decode(decoder: &Decoder, input: &Input, warn: impl Fn(Error)) -> Self;
520 }
521
522 impl<const N: usize> Decode<RawStr<N>> for String {
523     fn decode(decoder: &Decoder, input: &RawStr<N>, warn: impl Fn(Error)) -> Self {
524         decoder.decode_string(&input.0, &warn)
525     }
526 }
527
528 #[derive(Clone, Debug)]
529 pub struct HeaderRecord {
530     pub eye_catcher: String,
531     pub weight_index: Option<usize>,
532     pub n_cases: Option<u64>,
533     pub creation: NaiveDateTime,
534     pub file_label: String,
535 }
536
537 fn trim_end_spaces(mut s: String) -> String {
538     s.truncate(s.trim_end_matches(' ').len());
539     s
540 }
541
542 impl TryDecode for HeaderRecord {
543     type Input = crate::raw::HeaderRecord<RawString>;
544
545     fn try_decode(
546         decoder: &mut Decoder,
547         input: &Self::Input,
548         warn: impl Fn(Error),
549     ) -> Result<Option<Self>, Error> {
550         let eye_catcher = trim_end_spaces(decoder.decode_string(&input.eye_catcher.0, &warn));
551         let file_label = trim_end_spaces(decoder.decode_string(&input.file_label.0, &warn));
552         let creation_date = decoder.decode_string_cow(&input.creation_date.0, &warn);
553         let creation_date =
554             NaiveDate::parse_from_str(&creation_date, "%e %b %Y").unwrap_or_else(|_| {
555                 warn(Error::InvalidCreationDate {
556                     creation_date: creation_date.into(),
557                 });
558                 Default::default()
559             });
560         let creation_time = decoder.decode_string_cow(&input.creation_time.0, &warn);
561         let creation_time =
562             NaiveTime::parse_from_str(&creation_time, "%H:%M:%S").unwrap_or_else(|_| {
563                 warn(Error::InvalidCreationTime {
564                     creation_time: creation_time.into(),
565                 });
566                 Default::default()
567             });
568         Ok(Some(HeaderRecord {
569             eye_catcher,
570             weight_index: input.weight_index.map(|n| n as usize),
571             n_cases: input.n_cases.map(|n| n as u64),
572             creation: NaiveDateTime::new(creation_date, creation_time),
573             file_label,
574         }))
575     }
576 }
577
578 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
579 pub enum VarWidth {
580     Numeric,
581     String(u16),
582 }
583
584 impl PartialOrd for VarWidth {
585     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
586         match (self, other) {
587             (VarWidth::Numeric, VarWidth::Numeric) => Some(Ordering::Equal),
588             (VarWidth::String(a), VarWidth::String(b)) => Some(a.cmp(b)),
589             _ => None,
590         }
591     }
592 }
593
594 impl VarWidth {
595     const MAX_STRING: u16 = 32767;
596
597     fn n_dict_indexes(self) -> usize {
598         match self {
599             VarWidth::Numeric => 1,
600             VarWidth::String(w) => div_ceil(w as usize, 8),
601         }
602     }
603
604     fn width_predicate(
605         a: Option<VarWidth>,
606         b: Option<VarWidth>,
607         f: impl Fn(u16, u16) -> u16,
608     ) -> Option<VarWidth> {
609         match (a, b) {
610             (Some(VarWidth::Numeric), Some(VarWidth::Numeric)) => Some(VarWidth::Numeric),
611             (Some(VarWidth::String(a)), Some(VarWidth::String(b))) => {
612                 Some(VarWidth::String(f(a, b)))
613             }
614             _ => None,
615         }
616     }
617
618     /// Returns the wider of `self` and `other`:
619     /// - Numerical variable widths are equally wide.
620     /// - Longer strings are wider than shorter strings.
621     /// - Numerical and string types are incomparable, so result in `None`.
622     /// - Any `None` in the input yields `None` in the output.
623     pub fn wider(a: Option<VarWidth>, b: Option<VarWidth>) -> Option<VarWidth> {
624         Self::width_predicate(a, b, |a, b| a.max(b))
625     }
626
627     /// Returns the narrower of `self` and `other` (see [`Self::wider`]).
628     pub fn narrower(a: Option<VarWidth>, b: Option<VarWidth>) -> Option<VarWidth> {
629         Self::width_predicate(a, b, |a, b| a.min(b))
630     }
631 }
632
633 impl From<VarWidth> for VarType {
634     fn from(source: VarWidth) -> Self {
635         match source {
636             VarWidth::Numeric => VarType::Numeric,
637             VarWidth::String(_) => VarType::String,
638         }
639     }
640 }
641
642 #[derive(Clone, Debug)]
643 pub struct VariableRecord {
644     pub width: VarWidth,
645     pub name: Identifier,
646     pub print_format: Spec,
647     pub write_format: Spec,
648     pub missing_values: MissingValues,
649     pub label: Option<String>,
650 }
651
652 #[derive(Clone, Debug)]
653 pub struct MissingValues {
654     /// Individual missing values, up to 3 of them.
655     pub values: Vec<Value>,
656
657     /// Optional range of missing values.
658     pub range: Option<(Value, Value)>,
659 }
660
661 impl Decode<raw::MissingValues<RawStr<8>>> for MissingValues {
662     fn decode(
663         decoder: &Decoder,
664         input: &raw::MissingValues<RawStr<8>>,
665         _warn: impl Fn(Error),
666     ) -> Self {
667         MissingValues {
668             values: input
669                 .values
670                 .iter()
671                 .map(|value| Value::decode(value, decoder))
672                 .collect(),
673             range: input
674                 .range
675                 .as_ref()
676                 .map(|(low, high)| (Value::decode(low, decoder), Value::decode(high, decoder))),
677         }
678     }
679 }
680
681 fn decode_format(raw: raw::Spec, width: VarWidth, warn: impl Fn(Spec, FormatError)) -> Spec {
682     UncheckedSpec::try_from(raw)
683         .and_then(Spec::try_from)
684         .and_then(|x| x.check_width_compatibility(width))
685         .unwrap_or_else(|error| {
686             let new_format = Spec::default_for_width(width);
687             warn(new_format, error);
688             new_format
689         })
690 }
691
692 impl TryDecode for VariableRecord {
693     type Input = raw::VariableRecord<RawString, RawStr<8>>;
694
695     fn try_decode(
696         decoder: &mut Decoder,
697         input: &Self::Input,
698         warn: impl Fn(Error),
699     ) -> Result<Option<VariableRecord>, Error> {
700         let width = match input.width {
701             0 => VarWidth::Numeric,
702             w @ 1..=255 => VarWidth::String(w as u16),
703             -1 => return Ok(None),
704             _ => {
705                 return Err(Error::InvalidVariableWidth {
706                     offsets: input.offsets.clone(),
707                     width: input.width,
708                 })
709             }
710         };
711         let name = trim_end_spaces(decoder.decode_string(&input.name.0, &warn));
712         let name = match Identifier::new(&name, decoder.encoding) {
713             Ok(name) => {
714                 if !decoder.var_names.contains_key(&name) {
715                     name
716                 } else {
717                     let new_name = decoder.generate_name();
718                     warn(Error::DuplicateVariableName {
719                         duplicate_name: name.clone(),
720                         new_name: new_name.clone(),
721                     });
722                     new_name
723                 }
724             }
725             Err(id_error) => {
726                 let new_name = decoder.generate_name();
727                 warn(Error::InvalidVariableName {
728                     id_error,
729                     new_name: new_name.clone(),
730                 });
731                 new_name
732             }
733         };
734         let variable = Variable {
735             dict_index: decoder.n_dict_indexes,
736             short_name: name.clone(),
737             long_name: None,
738             width,
739         };
740         decoder.n_dict_indexes += width.n_dict_indexes();
741         assert!(decoder
742             .var_names
743             .insert(name.clone(), variable.dict_index)
744             .is_none());
745         assert!(decoder
746             .variables
747             .insert(variable.dict_index, variable)
748             .is_none());
749
750         let print_format = decode_format(input.print_format, width, |new_spec, format_error| {
751             warn(Error::InvalidPrintFormat {
752                 new_spec,
753                 variable: name.clone(),
754                 format_error,
755             })
756         });
757         let write_format = decode_format(input.write_format, width, |new_spec, format_error| {
758             warn(Error::InvalidWriteFormat {
759                 new_spec,
760                 variable: name.clone(),
761                 format_error,
762             })
763         });
764         let label = input
765             .label
766             .as_ref()
767             .map(|label| decoder.decode_string(&label.0, &warn));
768         Ok(Some(VariableRecord {
769             width,
770             name,
771             print_format,
772             write_format,
773             missing_values: MissingValues::decode(decoder, &input.missing_values, warn),
774             label,
775         }))
776     }
777 }
778
779 #[derive(Clone, Debug)]
780 pub struct DocumentRecord(Vec<String>);
781
782 impl TryDecode for DocumentRecord {
783     type Input = crate::raw::DocumentRecord<RawDocumentLine>;
784
785     fn try_decode(
786         decoder: &mut Decoder,
787         input: &Self::Input,
788         warn: impl Fn(Error),
789     ) -> Result<Option<Self>, Error> {
790         Ok(Some(DocumentRecord(
791             input
792                 .lines
793                 .iter()
794                 .map(|s| trim_end_spaces(decoder.decode_string(&s.0, &warn)))
795                 .collect(),
796         )))
797     }
798 }
799
800 trait TextRecord
801 where
802     Self: Sized,
803 {
804     const NAME: &'static str;
805     fn parse(input: &str, warn: impl Fn(Error)) -> Result<Self, Error>;
806 }
807
808 #[derive(Clone, Debug)]
809 pub struct VariableSet {
810     pub name: String,
811     pub vars: Vec<String>,
812 }
813
814 impl VariableSet {
815     fn parse(input: &str) -> Result<Self, Error> {
816         let (name, input) = input.split_once('=').ok_or(Error::TBD)?;
817         let vars = input.split_ascii_whitespace().map(String::from).collect();
818         Ok(VariableSet {
819             name: name.into(),
820             vars,
821         })
822     }
823 }
824
825 trait WarnOnError<T> {
826     fn warn_on_error<F: Fn(Error)>(self, warn: &F) -> Option<T>;
827 }
828 impl<T> WarnOnError<T> for Result<T, Error> {
829     fn warn_on_error<F: Fn(Error)>(self, warn: &F) -> Option<T> {
830         match self {
831             Ok(result) => Some(result),
832             Err(error) => {
833                 warn(error);
834                 None
835             }
836         }
837     }
838 }
839
840 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
841 pub enum Value {
842     Number(Option<OrderedFloat<f64>>),
843     String(String),
844 }
845
846 impl Value {
847     pub fn decode(raw: &raw::Value<RawStr<8>>, decoder: &Decoder) -> Self {
848         match raw {
849             raw::Value::Number(x) => Value::Number(x.map(|x| x.into())),
850             raw::Value::String(s) => Value::String(decoder.decode_exact_length(&s.0).into()),
851         }
852     }
853 }
854
855 #[derive(Clone, Debug)]
856 pub struct ValueLabel {
857     pub value: Value,
858     pub label: String,
859 }
860
861 #[derive(Clone, Debug)]
862 pub struct ValueLabelRecord {
863     pub var_type: VarType,
864     pub labels: Vec<ValueLabel>,
865     pub variables: Vec<Identifier>,
866 }
867
868 impl TryDecode for ValueLabelRecord {
869     type Input = crate::raw::ValueLabelRecord<RawStr<8>, RawString>;
870     fn try_decode(
871         decoder: &mut Decoder,
872         input: &Self::Input,
873         warn: impl Fn(Error),
874     ) -> Result<Option<ValueLabelRecord>, Error> {
875         let variables: Vec<&Variable> = input
876             .dict_indexes
877             .iter()
878             .filter_map(|&dict_index| {
879                 decoder
880                     .get_var_by_index(dict_index as usize)
881                     .warn_on_error(&warn)
882             })
883             .filter(|&variable| match variable.width {
884                 VarWidth::String(width) if width > 8 => {
885                     warn(Error::InvalidLongStringValueLabel(
886                         variable.short_name.clone(),
887                     ));
888                     false
889                 }
890                 _ => true,
891             })
892             .collect();
893         let mut i = variables.iter();
894         let Some(&first_var) = i.next() else {
895             return Ok(None);
896         };
897         let var_type: VarType = first_var.width.into();
898         for &variable in i {
899             let this_type: VarType = variable.width.into();
900             if var_type != this_type {
901                 let (numeric_var, string_var) = match var_type {
902                     VarType::Numeric => (first_var, variable),
903                     VarType::String => (variable, first_var),
904                 };
905                 warn(Error::ValueLabelsDifferentTypes {
906                     numeric_var: numeric_var.short_name.clone(),
907                     string_var: string_var.short_name.clone(),
908                 });
909                 return Ok(None);
910             }
911         }
912         let labels = input
913             .labels
914             .iter()
915             .map(|raw::ValueLabel { value, label }| {
916                 let label = decoder.decode_string(&label.0, &warn);
917                 let value = Value::decode(
918                     value,
919                     decoder,
920                 );
921                 ValueLabel { value, label }
922             })
923             .collect();
924         let variables = variables
925             .iter()
926             .map(|&variable| variable.short_name.clone())
927             .collect();
928         Ok(Some(ValueLabelRecord {
929             var_type,
930             labels,
931             variables,
932         }))
933     }
934 }
935
936 #[derive(Clone, Debug)]
937 pub struct VariableSetRecord(Vec<VariableSet>);
938
939 impl TextRecord for VariableSetRecord {
940     const NAME: &'static str = "variable set";
941     fn parse(input: &str, warn: impl Fn(Error)) -> Result<Self, Error> {
942         let mut sets = Vec::new();
943         for line in input.lines() {
944             if let Some(set) = VariableSet::parse(line).warn_on_error(&warn) {
945                 sets.push(set)
946             }
947         }
948         Ok(VariableSetRecord(sets))
949     }
950 }
951
952 #[derive(Clone, Debug)]
953 pub struct ProductInfoRecord(pub String);
954
955 impl TextRecord for ProductInfoRecord {
956     const NAME: &'static str = "extra product info";
957     fn parse(input: &str, _warn: impl Fn(Error)) -> Result<Self, Error> {
958         Ok(ProductInfoRecord(input.into()))
959     }
960 }
961
962 #[derive(Clone, Debug)]
963 pub struct LongName {
964     pub short_name: Identifier,
965     pub long_name: Identifier,
966 }
967
968 impl LongName {
969     fn new(decoder: &mut Decoder, short_name: &str, long_name: &str) -> Result<LongName, Error> {
970         let short_name =
971             Identifier::new(short_name, decoder.encoding).map_err(Error::InvalidShortName)?;
972         let long_name =
973             Identifier::new(long_name, decoder.encoding).map_err(Error::InvalidLongName)?;
974         Ok(LongName {
975             short_name,
976             long_name,
977         })
978     }
979 }
980
981 #[derive(Clone, Debug)]
982 pub struct LongNameRecord(Vec<LongName>);
983
984 impl LongNameRecord {
985     pub fn parse(decoder: &mut Decoder, input: &str, warn: impl Fn(Error)) -> Result<Self, Error> {
986         let mut names = Vec::new();
987         for pair in input.split('\t').filter(|s| !s.is_empty()) {
988             if let Some((short_name, long_name)) = pair.split_once('=') {
989                 if let Some(long_name) =
990                     LongName::new(decoder, short_name, long_name).warn_on_error(&warn)
991                 {
992                     names.push(long_name);
993                 }
994             } else {
995                 warn(Error::TBD)
996             }
997         }
998         Ok(LongNameRecord(names))
999     }
1000 }
1001
1002 #[derive(Clone, Debug)]
1003 pub struct VeryLongString {
1004     pub short_name: Identifier,
1005     pub length: u16,
1006 }
1007
1008 impl VeryLongString {
1009     fn parse(decoder: &Decoder, input: &str) -> Result<VeryLongString, Error> {
1010         let Some((short_name, length)) = input.split_once('=') else {
1011             return Err(Error::TBD);
1012         };
1013         let short_name =
1014             Identifier::new(short_name, decoder.encoding).map_err(Error::InvalidLongStringName)?;
1015         let length: u16 = length.parse().map_err(|_| Error::TBD)?;
1016         if length > VarWidth::MAX_STRING {
1017             return Err(Error::TBD);
1018         }
1019         Ok(VeryLongString { short_name, length })
1020     }
1021 }
1022
1023 #[derive(Clone, Debug)]
1024 pub struct VeryLongStringRecord(Vec<VeryLongString>);
1025
1026 impl VeryLongStringRecord {
1027     pub fn parse(decoder: &Decoder, input: &str, warn: impl Fn(Error)) -> Result<Self, Error> {
1028         let mut very_long_strings = Vec::new();
1029         for tuple in input
1030             .split('\0')
1031             .map(|s| s.trim_end_matches('\t'))
1032             .filter(|s| !s.is_empty())
1033         {
1034             if let Some(vls) = VeryLongString::parse(decoder, tuple).warn_on_error(&warn) {
1035                 very_long_strings.push(vls)
1036             }
1037         }
1038         Ok(VeryLongStringRecord(very_long_strings))
1039     }
1040 }
1041
1042 #[derive(Clone, Debug)]
1043 pub struct Attribute {
1044     pub name: Identifier,
1045     pub values: Vec<String>,
1046 }
1047
1048 impl Attribute {
1049     fn parse<'a>(
1050         decoder: &Decoder,
1051         input: &'a str,
1052         warn: &impl Fn(Error),
1053     ) -> Result<(Option<Attribute>, &'a str), Error> {
1054         let Some((name, mut input)) = input.split_once('(') else {
1055             return Err(Error::TBD);
1056         };
1057         let mut values = Vec::new();
1058         loop {
1059             let Some((value, rest)) = input.split_once('\n') else {
1060                 return Err(Error::TBD);
1061             };
1062             if let Some(stripped) = value
1063                 .strip_prefix('\'')
1064                 .and_then(|value| value.strip_suffix('\''))
1065             {
1066                 values.push(stripped.into());
1067             } else {
1068                 warn(Error::TBD);
1069                 values.push(value.into());
1070             }
1071             if let Some(rest) = rest.strip_prefix(')') {
1072                 let attribute = Identifier::new(name, decoder.encoding)
1073                     .map_err(Error::InvalidAttributeName)
1074                     .warn_on_error(warn)
1075                     .map(|name| Attribute { name, values });
1076                 return Ok((attribute, rest));
1077             };
1078             input = rest;
1079         }
1080     }
1081 }
1082
1083 #[derive(Clone, Debug)]
1084 pub struct AttributeSet(pub Vec<Attribute>);
1085
1086 impl AttributeSet {
1087     fn parse<'a>(
1088         decoder: &Decoder,
1089         mut input: &'a str,
1090         sentinel: Option<char>,
1091         warn: &impl Fn(Error),
1092     ) -> Result<(AttributeSet, &'a str), Error> {
1093         let mut attributes = Vec::new();
1094         let rest = loop {
1095             match input.chars().next() {
1096                 None => break input,
1097                 c if c == sentinel => break &input[1..],
1098                 _ => {
1099                     let (attribute, rest) = Attribute::parse(decoder, input, &warn)?;
1100                     if let Some(attribute) = attribute {
1101                         attributes.push(attribute);
1102                     }
1103                     input = rest;
1104                 }
1105             }
1106         };
1107         Ok((AttributeSet(attributes), rest))
1108     }
1109 }
1110
1111 #[derive(Clone, Debug)]
1112 pub struct FileAttributeRecord(AttributeSet);
1113
1114 impl FileAttributeRecord {
1115     pub fn parse(decoder: &Decoder, input: &str, warn: impl Fn(Error)) -> Result<Self, Error> {
1116         let (set, rest) = AttributeSet::parse(decoder, input, None, &warn)?;
1117         if !rest.is_empty() {
1118             warn(Error::TBD);
1119         }
1120         Ok(FileAttributeRecord(set))
1121     }
1122 }
1123
1124 #[derive(Clone, Debug)]
1125 pub struct VarAttributeSet {
1126     pub long_var_name: Identifier,
1127     pub attributes: AttributeSet,
1128 }
1129
1130 impl VarAttributeSet {
1131     fn parse<'a>(
1132         decoder: &Decoder,
1133         input: &'a str,
1134         warn: &impl Fn(Error),
1135     ) -> Result<(Option<VarAttributeSet>, &'a str), Error> {
1136         let Some((long_var_name, rest)) = input.split_once(':') else {
1137             return Err(Error::TBD);
1138         };
1139         let (attributes, rest) = AttributeSet::parse(decoder, rest, Some('/'), warn)?;
1140         let var_attribute = Identifier::new(long_var_name, decoder.encoding)
1141             .map_err(Error::InvalidAttributeVariableName)
1142             .warn_on_error(warn)
1143             .map(|name| VarAttributeSet {
1144                 long_var_name: name,
1145                 attributes,
1146             });
1147         Ok((var_attribute, rest))
1148     }
1149 }
1150
1151 #[derive(Clone, Debug)]
1152 pub struct VariableAttributeRecord(Vec<VarAttributeSet>);
1153
1154 impl VariableAttributeRecord {
1155     pub fn parse(decoder: &Decoder, mut input: &str, warn: impl Fn(Error)) -> Result<Self, Error> {
1156         let mut var_attribute_sets = Vec::new();
1157         while !input.is_empty() {
1158             let Some((var_attribute, rest)) =
1159                 VarAttributeSet::parse(decoder, input, &warn).warn_on_error(&warn)
1160             else {
1161                 break;
1162             };
1163             if let Some(var_attribute) = var_attribute {
1164                 var_attribute_sets.push(var_attribute);
1165             }
1166             input = rest;
1167         }
1168         Ok(VariableAttributeRecord(var_attribute_sets))
1169     }
1170 }
1171
1172 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1173 pub enum Measure {
1174     Nominal,
1175     Ordinal,
1176     Scale,
1177 }
1178
1179 impl Measure {
1180     fn try_decode(source: u32) -> Result<Option<Measure>, Error> {
1181         match source {
1182             0 => Ok(None),
1183             1 => Ok(Some(Measure::Nominal)),
1184             2 => Ok(Some(Measure::Ordinal)),
1185             3 => Ok(Some(Measure::Scale)),
1186             _ => Err(Error::InvalidMeasurement(source)),
1187         }
1188     }
1189 }
1190
1191 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1192 pub enum Alignment {
1193     Left,
1194     Right,
1195     Center,
1196 }
1197
1198 impl Alignment {
1199     fn try_decode(source: u32) -> Result<Option<Alignment>, Error> {
1200         match source {
1201             0 => Ok(None),
1202             1 => Ok(Some(Alignment::Left)),
1203             2 => Ok(Some(Alignment::Right)),
1204             3 => Ok(Some(Alignment::Center)),
1205             _ => Err(Error::InvalidAlignment(source)),
1206         }
1207     }
1208 }
1209
1210 #[derive(Clone, Debug)]
1211 pub struct VarDisplay {
1212     pub measure: Option<Measure>,
1213     pub width: Option<u32>,
1214     pub alignment: Option<Alignment>,
1215 }
1216
1217 #[derive(Clone, Debug)]
1218 pub struct VarDisplayRecord(pub Vec<VarDisplay>);
1219
1220 impl TryDecode for VarDisplayRecord {
1221     type Input = raw::VarDisplayRecord;
1222     fn try_decode(
1223         decoder: &mut Decoder,
1224         input: &Self::Input,
1225         warn: impl Fn(Error),
1226     ) -> Result<Option<Self>, Error> {
1227         let n_vars = decoder.variables.len();
1228         let n_per_var = if input.0.len() == 3 * n_vars {
1229             3
1230         } else if input.0.len() == 2 * n_vars {
1231             2
1232         } else {
1233             return Err(Error::TBD);
1234         };
1235
1236         let var_displays = input
1237             .0
1238             .chunks(n_per_var)
1239             .map(|chunk| {
1240                 let (measure, width, alignment) = match n_per_var == 3 {
1241                     true => (chunk[0], Some(chunk[1]), chunk[2]),
1242                     false => (chunk[0], None, chunk[1]),
1243                 };
1244                 let measure = Measure::try_decode(measure).warn_on_error(&warn).flatten();
1245                 let alignment = Alignment::try_decode(alignment)
1246                     .warn_on_error(&warn)
1247                     .flatten();
1248                 VarDisplay {
1249                     measure,
1250                     width,
1251                     alignment,
1252                 }
1253             })
1254             .collect();
1255         Ok(Some(VarDisplayRecord(var_displays)))
1256     }
1257 }
1258
1259 #[derive(Clone, Debug)]
1260 pub enum MultipleResponseType {
1261     MultipleDichotomy {
1262         value: Value,
1263         labels: CategoryLabels,
1264     },
1265     MultipleCategory,
1266 }
1267
1268 impl MultipleResponseType {
1269     fn decode(
1270         decoder: &Decoder,
1271         mr_set: &Identifier,
1272         input: &raw::MultipleResponseType,
1273         min_width: VarWidth,
1274         warn: &impl Fn(Error),
1275     ) -> Result<Self, Error> {
1276         let mr_type = match input {
1277             raw::MultipleResponseType::MultipleDichotomy { value, labels } => {
1278                 let value = decoder.decode_string_cow(&value.0, warn);
1279                 let value = match min_width {
1280                     VarWidth::Numeric => {
1281                         let number: f64 = value.trim().parse().map_err(|_| {
1282                             Error::InvalidMDGroupCountedValue {
1283                                 mr_set: mr_set.clone(),
1284                                 number: value.into(),
1285                             }
1286                         })?;
1287                         Value::Number(Some(number.into()))
1288                     }
1289                     VarWidth::String(max_width) => {
1290                         let value = value.trim_end_matches(' ');
1291                         let width = value.len();
1292                         if width > max_width as usize {
1293                             return Err(Error::TooWideMDGroupCountedValue {
1294                                 mr_set: mr_set.clone(),
1295                                 value: value.into(),
1296                                 width,
1297                                 max_width,
1298                             });
1299                         };
1300                         Value::String(value.into())
1301                     }
1302                 };
1303                 MultipleResponseType::MultipleDichotomy {
1304                     value,
1305                     labels: *labels,
1306                 }
1307             }
1308             raw::MultipleResponseType::MultipleCategory => MultipleResponseType::MultipleCategory,
1309         };
1310         Ok(mr_type)
1311     }
1312 }
1313
1314 #[derive(Clone, Debug)]
1315 pub struct MultipleResponseSet {
1316     pub name: Identifier,
1317     pub min_width: VarWidth,
1318     pub max_width: VarWidth,
1319     pub label: String,
1320     pub mr_type: MultipleResponseType,
1321     pub dict_indexes: Vec<DictIndex>,
1322 }
1323
1324 impl MultipleResponseSet {
1325     fn decode(
1326         decoder: &Decoder,
1327         input: &raw::MultipleResponseSet,
1328         warn: &impl Fn(Error),
1329     ) -> Result<Self, Error> {
1330         let mr_set_name = decoder
1331             .decode_identifier(&input.name.0, warn)
1332             .map_err(Error::InvalidMrSetName)?;
1333
1334         let label = decoder.decode_string(&input.label.0, warn);
1335
1336         let mut dict_indexes = Vec::with_capacity(input.short_names.len());
1337         for short_name in input.short_names.iter() {
1338             let short_name = match decoder.decode_identifier(&short_name.0, warn) {
1339                 Ok(name) => name,
1340                 Err(error) => {
1341                     warn(Error::InvalidMrSetName(error));
1342                     continue;
1343                 }
1344             };
1345             let Some(&dict_index) = decoder.var_names.get(&short_name) else {
1346                 warn(Error::UnknownMrSetVariable {
1347                     mr_set: mr_set_name.clone(),
1348                     short_name: short_name.clone(),
1349                 });
1350                 continue;
1351             };
1352             dict_indexes.push(dict_index);
1353         }
1354
1355         match dict_indexes.len() {
1356             0 => return Err(Error::EmptyMrSet(mr_set_name)),
1357             1 => return Err(Error::OneVarMrSet(mr_set_name)),
1358             _ => (),
1359         }
1360
1361         let Some((Some(min_width), Some(max_width))) = dict_indexes
1362             .iter()
1363             .map(|dict_index| decoder.variables[dict_index].width)
1364             .map(|w| (Some(w), Some(w)))
1365             .reduce(|(na, wa), (nb, wb)| (VarWidth::narrower(na, nb), VarWidth::wider(wa, wb)))
1366         else {
1367             return Err(Error::MixedMrSet(mr_set_name));
1368         };
1369
1370         let mr_type =
1371             MultipleResponseType::decode(decoder, &mr_set_name, &input.mr_type, min_width, warn)?;
1372
1373         Ok(MultipleResponseSet {
1374             name: mr_set_name,
1375             min_width,
1376             max_width,
1377             label,
1378             mr_type,
1379             dict_indexes,
1380         })
1381     }
1382 }
1383
1384 #[derive(Clone, Debug)]
1385 pub struct MultipleResponseRecord(pub Vec<MultipleResponseSet>);
1386
1387 impl TryDecode for MultipleResponseRecord {
1388     type Input = raw::MultipleResponseRecord;
1389
1390     fn try_decode(
1391         decoder: &mut Decoder,
1392         input: &Self::Input,
1393         warn: impl Fn(Error),
1394     ) -> Result<Option<Self>, Error> {
1395         let mut sets = Vec::with_capacity(input.0.len());
1396         for set in &input.0 {
1397             match MultipleResponseSet::decode(decoder, set, &warn) {
1398                 Ok(set) => sets.push(set),
1399                 Err(error) => warn(error),
1400             }
1401         }
1402         Ok(Some(MultipleResponseRecord(sets)))
1403     }
1404 }
1405
1406 #[derive(Clone, Debug)]
1407 pub struct LongStringMissingValues {
1408     /// Variable name.
1409     pub var_name: Identifier,
1410
1411     /// Missing values.
1412     pub missing_values: MissingValues,
1413 }
1414
1415 impl LongStringMissingValues {
1416     fn decode(
1417         decoder: &Decoder,
1418         input: &raw::LongStringMissingValues,
1419         warn: &impl Fn(Error),
1420     ) -> Result<Self, Error> {
1421         let var_name = decoder.decode_string(&input.var_name.0, warn);
1422         let var_name = Identifier::new(var_name.trim_end(), decoder.encoding)
1423             .map_err(Error::InvalidLongStringValueLabelName)?;
1424
1425         let missing_values = MissingValues::decode(decoder, &input.missing_values, warn);
1426
1427         Ok(LongStringMissingValues {
1428             var_name,
1429             missing_values,
1430         })
1431     }
1432 }
1433
1434 #[derive(Clone, Debug)]
1435 pub struct LongStringMissingValuesRecord(Vec<LongStringMissingValues>);
1436
1437 impl TryDecode for LongStringMissingValuesRecord {
1438     type Input = raw::LongStringMissingValueRecord;
1439
1440     fn try_decode(
1441         decoder: &mut Decoder,
1442         input: &Self::Input,
1443         warn: impl Fn(Error),
1444     ) -> Result<Option<Self>, Error> {
1445         let mut labels = Vec::with_capacity(input.0.len());
1446         for label in &input.0 {
1447             match LongStringMissingValues::decode(decoder, label, &warn) {
1448                 Ok(set) => labels.push(set),
1449                 Err(error) => warn(error),
1450             }
1451         }
1452         Ok(Some(LongStringMissingValuesRecord(labels)))
1453     }
1454 }
1455
1456 #[derive(Clone, Debug)]
1457 pub struct LongStringValueLabels {
1458     pub var_name: Identifier,
1459     pub width: VarWidth,
1460     pub labels: Vec<ValueLabel>,
1461 }
1462
1463 impl LongStringValueLabels {
1464     fn decode(
1465         decoder: &Decoder,
1466         input: &raw::LongStringValueLabels,
1467         warn: &impl Fn(Error),
1468     ) -> Result<Self, Error> {
1469         let var_name = decoder.decode_string(&input.var_name.0, warn);
1470         let var_name = Identifier::new(var_name.trim_end(), decoder.encoding)
1471             .map_err(Error::InvalidLongStringValueLabelName)?;
1472
1473         let min_width = 9;
1474         let max_width = VarWidth::MAX_STRING;
1475         if input.width < 9 || input.width > max_width as u32 {
1476             return Err(Error::InvalidLongValueLabelWidth {
1477                 name: var_name,
1478                 width: input.width,
1479                 min_width,
1480                 max_width,
1481             });
1482         }
1483         let width = input.width as u16;
1484
1485         let mut labels = Vec::with_capacity(input.labels.len());
1486         for (value, label) in input.labels.iter() {
1487             let value = Value::String(decoder.decode_exact_length(&value.0).into());
1488             let label = decoder.decode_string(&label.0, warn);
1489             labels.push(ValueLabel { value, label });
1490         }
1491
1492         Ok(LongStringValueLabels {
1493             var_name,
1494             width: VarWidth::String(width),
1495             labels,
1496         })
1497     }
1498 }
1499
1500 #[derive(Clone, Debug)]
1501 pub struct LongStringValueLabelRecord(pub Vec<LongStringValueLabels>);
1502
1503 impl TryDecode for LongStringValueLabelRecord {
1504     type Input = raw::LongStringValueLabelRecord;
1505
1506     fn try_decode(
1507         decoder: &mut Decoder,
1508         input: &Self::Input,
1509         warn: impl Fn(Error),
1510     ) -> Result<Option<Self>, Error> {
1511         let mut labels = Vec::with_capacity(input.0.len());
1512         for label in &input.0 {
1513             match LongStringValueLabels::decode(decoder, label, &warn) {
1514                 Ok(set) => labels.push(set),
1515                 Err(error) => warn(error),
1516             }
1517         }
1518         Ok(Some(LongStringValueLabelRecord(labels)))
1519     }
1520 }
1521
1522 #[cfg(test)]
1523 mod test {
1524     use encoding_rs::WINDOWS_1252;
1525
1526     #[test]
1527     fn test() {
1528         let mut s = String::new();
1529         s.push(char::REPLACEMENT_CHARACTER);
1530         let encoded = WINDOWS_1252.encode(&s).0;
1531         let decoded = WINDOWS_1252.decode(&encoded[..]).0;
1532         println!("{:?}", decoded);
1533     }
1534
1535     #[test]
1536     fn test2() {
1537         let charset: Vec<u8> = (0..=255).collect();
1538         println!("{}", charset.len());
1539         let decoded = WINDOWS_1252.decode(&charset[..]).0;
1540         println!("{}", decoded.len());
1541         let encoded = WINDOWS_1252.encode(&decoded[..]).0;
1542         println!("{}", encoded.len());
1543         assert_eq!(&charset[..], &encoded[..]);
1544     }
1545 }