work
[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, UnencodedStr, VarType},
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>,
216     variables: Vec<&'a raw::VariableRecord>,
217     value_labels: Vec<&'a raw::ValueLabelRecord>,
218     document: Option<&'a raw::DocumentRecord>,
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 decoder = Decoder {
312         compression: header.compression,
313         endian: header.endian,
314         encoding,
315         variables: HashMap::new(),
316         var_names: HashMap::new(),
317         n_dict_indexes: 0,
318         n_generated_names: 0,
319     };
320
321     let mut output = Vec::with_capacity(headers.len());
322
323     // Decode the records that don't use variables at all.
324     if let Some(header) = HeaderRecord::try_decode(&mut decoder, header, warn)? {
325         output.push(Record::Header(header))
326     }
327     if let Some(raw) = h.document {
328         if let Some(document) = DocumentRecord::try_decode(&mut decoder, raw, warn)? {
329             output.push(Record::Document(document))
330         }
331     }
332     if let Some(raw) = h.integer_info {
333         output.push(Record::IntegerInfo(raw.clone()));
334     }
335     if let Some(raw) = h.float_info {
336         output.push(Record::FloatInfo(raw.clone()));
337     }
338     if let Some(raw) = h.product_info {
339         let s = decoder.decode_string_cow(&raw.text.0, warn);
340         output.push(Record::ProductInfo(ProductInfoRecord::parse(&s, warn)?));
341     }
342     if let Some(raw) = h.number_of_cases {
343         output.push(Record::NumberOfCases(raw.clone()))
344     }
345     for &raw in &h.file_attributes {
346         let s = decoder.decode_string_cow(&raw.text.0, warn);
347         output.push(Record::FileAttributes(FileAttributeRecord::parse(
348             &decoder, &s, warn,
349         )?));
350     }
351     for &raw in &h.other_extensions {
352         output.push(Record::OtherExtension(raw.clone()));
353     }
354
355     // Decode the variable records, which are the basis of almost everything
356     // else.
357     for &raw in &h.variables {
358         if let Some(variable) = VariableRecord::try_decode(&mut decoder, raw, warn)? {
359             output.push(Record::Variable(variable));
360         }
361     }
362
363     // Decode value labels and weight variable.  These use indexes into the
364     // variable records, so we need to parse them before those indexes become
365     // invalidated by very long string variables.
366     for &raw in &h.value_labels {
367         if let Some(value_label) = ValueLabelRecord::try_decode(&mut decoder, raw, warn)? {
368             output.push(Record::ValueLabel(value_label));
369         }
370     }
371     // XXX weight
372     if let Some(raw) = h.var_display {
373         if let Some(vdr) = VarDisplayRecord::try_decode(&mut decoder, raw, warn)? {
374             output.push(Record::VarDisplay(vdr))
375         }
376     }
377
378     // Decode records that use short names.
379     for &raw in &h.multiple_response {
380         if let Some(mrr) = MultipleResponseRecord::try_decode(&mut decoder, raw, warn)? {
381             output.push(Record::MultipleResponse(mrr))
382         }
383     }
384     for &raw in &h.very_long_strings {
385         let s = decoder.decode_string_cow(&raw.text.0, warn);
386         output.push(Record::VeryLongStrings(VeryLongStringRecord::parse(
387             &decoder, &s, warn,
388         )?));
389     }
390
391     // Rename variables to their long names.
392     for &raw in &h.long_names {
393         let s = decoder.decode_string_cow(&raw.text.0, warn);
394         output.push(Record::LongNames(LongNameRecord::parse(
395             &mut decoder,
396             &s,
397             warn,
398         )?));
399     }
400
401     // Decode recods that use long names.
402     for &raw in &h.variable_attributes {
403         let s = decoder.decode_string_cow(&raw.text.0, warn);
404         output.push(Record::VariableAttributes(VariableAttributeRecord::parse(
405             &decoder, &s, warn,
406         )?));
407     }
408     for &raw in &h.long_string_value_labels {
409         if let Some(mrr) = LongStringValueLabelRecord::try_decode(&mut decoder, raw, warn)? {
410             output.push(Record::LongStringValueLabels(mrr))
411         }
412     }
413     for &raw in &h.long_string_missing_values {
414         if let Some(mrr) = LongStringMissingValuesRecord::try_decode(&mut decoder, raw, warn)? {
415             output.push(Record::LongStringMissingValues(mrr))
416         }
417     }
418     for &raw in &h.variable_sets {
419         let s = decoder.decode_string_cow(&raw.text.0, warn);
420         output.push(Record::VariableSets(VariableSetRecord::parse(&s, warn)?));
421     }
422     Ok(output)
423 }
424
425 impl Decoder {
426     fn generate_name(&mut self) -> Identifier {
427         loop {
428             self.n_generated_names += 1;
429             let name = Identifier::new(&format!("VAR{:03}", self.n_generated_names), self.encoding)
430                 .unwrap();
431             if !self.var_names.contains_key(&name) {
432                 return name;
433             }
434             assert!(self.n_generated_names < usize::MAX);
435         }
436     }
437     fn decode_string_cow<'a>(&self, input: &'a [u8], warn: &impl Fn(Error)) -> Cow<'a, str> {
438         let (output, malformed) = self.encoding.decode_without_bom_handling(input);
439         if malformed {
440             warn(Error::MalformedString {
441                 encoding: self.encoding.name().into(),
442                 text: output.clone().into(),
443             });
444         }
445         output
446     }
447     fn decode_string(&self, input: &[u8], warn: &impl Fn(Error)) -> String {
448         self.decode_string_cow(input, warn).into()
449     }
450     pub fn decode_identifier(
451         &self,
452         input: &[u8],
453         warn: &impl Fn(Error),
454     ) -> Result<Identifier, IdError> {
455         let s = self.decode_string_cow(input, warn);
456         Identifier::new(&s, self.encoding)
457     }
458     fn get_var_by_index(&self, dict_index: usize) -> Result<&Variable, Error> {
459         let max_index = self.n_dict_indexes;
460         if dict_index == 0 || dict_index > max_index {
461             return Err(Error::InvalidDictIndex {
462                 dict_index,
463                 max_index,
464             });
465         }
466         let Some(variable) = self.variables.get(&(dict_index - 1)) else {
467             return Err(Error::DictIndexIsContinuation(dict_index));
468         };
469         Ok(variable)
470     }
471
472     /// Returns `input` decoded from `self.encoding` into UTF-8 such that
473     /// re-encoding the result back into `self.encoding` will have exactly the
474     /// same length in bytes.
475     ///
476     /// XXX warn about errors?
477     fn decode_exact_length<'a>(&self, input: &'a [u8]) -> Cow<'a, str> {
478         if let (s, false) = self.encoding.decode_without_bom_handling(input) {
479             // This is the common case.  Usually there will be no errors.
480             s
481         } else {
482             // Unusual case.  Don't bother to optimize it much.
483             let mut decoder = self.encoding.new_decoder_without_bom_handling();
484             let mut output = String::with_capacity(
485                 decoder
486                     .max_utf8_buffer_length_without_replacement(input.len())
487                     .unwrap(),
488             );
489             let mut rest = input;
490             while !rest.is_empty() {
491                 match decoder.decode_to_string_without_replacement(rest, &mut output, true) {
492                     (DecoderResult::InputEmpty, _) => break,
493                     (DecoderResult::OutputFull, _) => unreachable!(),
494                     (DecoderResult::Malformed(a, b), consumed) => {
495                         let skipped = a as usize + b as usize;
496                         output.extend(repeat('?').take(skipped));
497                         rest = &rest[consumed..];
498                     }
499                 }
500             }
501             assert_eq!(self.encoding.encode(&output).0.len(), input.len());
502             output.into()
503         }
504     }
505 }
506
507 pub trait TryDecode: Sized {
508     type Input;
509     fn try_decode(
510         decoder: &mut Decoder,
511         input: &Self::Input,
512         warn: impl Fn(Error),
513     ) -> Result<Option<Self>, Error>;
514 }
515
516 pub trait Decode<Input>: Sized {
517     fn decode(decoder: &Decoder, input: &Input, warn: impl Fn(Error)) -> Self;
518 }
519
520 impl<const N: usize> Decode<UnencodedStr<N>> for String {
521     fn decode(decoder: &Decoder, input: &UnencodedStr<N>, warn: impl Fn(Error)) -> Self {
522         decoder.decode_string(&input.0, &warn)
523     }
524 }
525
526 #[derive(Clone, Debug)]
527 pub struct HeaderRecord {
528     pub eye_catcher: String,
529     pub weight_index: Option<usize>,
530     pub n_cases: Option<u64>,
531     pub creation: NaiveDateTime,
532     pub file_label: String,
533 }
534
535 fn trim_end_spaces(mut s: String) -> String {
536     s.truncate(s.trim_end_matches(' ').len());
537     s
538 }
539
540 impl TryDecode for HeaderRecord {
541     type Input = crate::raw::HeaderRecord;
542
543     fn try_decode(
544         decoder: &mut Decoder,
545         input: &Self::Input,
546         warn: impl Fn(Error),
547     ) -> Result<Option<Self>, Error> {
548         let eye_catcher = trim_end_spaces(decoder.decode_string(&input.eye_catcher.0, &warn));
549         let file_label = trim_end_spaces(decoder.decode_string(&input.file_label.0, &warn));
550         let creation_date = decoder.decode_string_cow(&input.creation_date.0, &warn);
551         let creation_date =
552             NaiveDate::parse_from_str(&creation_date, "%e %b %Y").unwrap_or_else(|_| {
553                 warn(Error::InvalidCreationDate {
554                     creation_date: creation_date.into(),
555                 });
556                 Default::default()
557             });
558         let creation_time = decoder.decode_string_cow(&input.creation_time.0, &warn);
559         let creation_time =
560             NaiveTime::parse_from_str(&creation_time, "%H:%M:%S").unwrap_or_else(|_| {
561                 warn(Error::InvalidCreationTime {
562                     creation_time: creation_time.into(),
563                 });
564                 Default::default()
565             });
566         Ok(Some(HeaderRecord {
567             eye_catcher,
568             weight_index: input.weight_index.map(|n| n as usize),
569             n_cases: input.n_cases.map(|n| n as u64),
570             creation: NaiveDateTime::new(creation_date, creation_time),
571             file_label,
572         }))
573     }
574 }
575
576 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
577 pub enum VarWidth {
578     Numeric,
579     String(u16),
580 }
581
582 impl PartialOrd for VarWidth {
583     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
584         match (self, other) {
585             (VarWidth::Numeric, VarWidth::Numeric) => Some(Ordering::Equal),
586             (VarWidth::String(a), VarWidth::String(b)) => Some(a.cmp(b)),
587             _ => None,
588         }
589     }
590 }
591
592 impl VarWidth {
593     const MAX_STRING: u16 = 32767;
594
595     fn n_dict_indexes(self) -> usize {
596         match self {
597             VarWidth::Numeric => 1,
598             VarWidth::String(w) => div_ceil(w as usize, 8),
599         }
600     }
601
602     fn width_predicate(
603         a: Option<VarWidth>,
604         b: Option<VarWidth>,
605         f: impl Fn(u16, u16) -> u16,
606     ) -> Option<VarWidth> {
607         match (a, b) {
608             (Some(VarWidth::Numeric), Some(VarWidth::Numeric)) => Some(VarWidth::Numeric),
609             (Some(VarWidth::String(a)), Some(VarWidth::String(b))) => {
610                 Some(VarWidth::String(f(a, b)))
611             }
612             _ => None,
613         }
614     }
615
616     /// Returns the wider of `self` and `other`:
617     /// - Numerical variable widths are equally wide.
618     /// - Longer strings are wider than shorter strings.
619     /// - Numerical and string types are incomparable, so result in `None`.
620     /// - Any `None` in the input yields `None` in the output.
621     pub fn wider(a: Option<VarWidth>, b: Option<VarWidth>) -> Option<VarWidth> {
622         Self::width_predicate(a, b, |a, b| a.max(b))
623     }
624
625     /// Returns the narrower of `self` and `other` (see [`Self::wider`]).
626     pub fn narrower(a: Option<VarWidth>, b: Option<VarWidth>) -> Option<VarWidth> {
627         Self::width_predicate(a, b, |a, b| a.min(b))
628     }
629 }
630
631 impl From<VarWidth> for VarType {
632     fn from(source: VarWidth) -> Self {
633         match source {
634             VarWidth::Numeric => VarType::Numeric,
635             VarWidth::String(_) => VarType::String,
636         }
637     }
638 }
639
640 #[derive(Clone, Debug)]
641 pub struct VariableRecord {
642     pub width: VarWidth,
643     pub name: Identifier,
644     pub print_format: Spec,
645     pub write_format: Spec,
646     pub missing_values: MissingValues,
647     pub label: Option<String>,
648 }
649
650 #[derive(Clone, Debug)]
651 pub struct MissingValues {
652     /// Individual missing values, up to 3 of them.
653     pub values: Vec<Value>,
654
655     /// Optional range of missing values.
656     pub range: Option<(Value, Value)>,
657 }
658
659 impl Decode<raw::MissingValues> for MissingValues {
660     fn decode(decoder: &Decoder, input: &raw::MissingValues, _warn: impl Fn(Error)) -> Self {
661         MissingValues {
662             values: input
663                 .values
664                 .iter()
665                 .map(|value| Value::decode(value, decoder))
666                 .collect(),
667             range: input
668                 .range
669                 .as_ref()
670                 .map(|(low, high)| (Value::decode(low, decoder), Value::decode(high, decoder))),
671         }
672     }
673 }
674
675 fn decode_format(raw: raw::Spec, width: VarWidth, warn: impl Fn(Spec, FormatError)) -> Spec {
676     UncheckedSpec::try_from(raw)
677         .and_then(Spec::try_from)
678         .and_then(|x| x.check_width_compatibility(width))
679         .unwrap_or_else(|error| {
680             let new_format = Spec::default_for_width(width);
681             warn(new_format, error);
682             new_format
683         })
684 }
685
686 impl TryDecode for VariableRecord {
687     type Input = raw::VariableRecord;
688
689     fn try_decode(
690         decoder: &mut Decoder,
691         input: &crate::raw::VariableRecord,
692         warn: impl Fn(Error),
693     ) -> Result<Option<VariableRecord>, Error> {
694         let width = match input.width {
695             0 => VarWidth::Numeric,
696             w @ 1..=255 => VarWidth::String(w as u16),
697             -1 => return Ok(None),
698             _ => {
699                 return Err(Error::InvalidVariableWidth {
700                     offsets: input.offsets.clone(),
701                     width: input.width,
702                 })
703             }
704         };
705         let name = trim_end_spaces(decoder.decode_string(&input.name.0, &warn));
706         let name = match Identifier::new(&name, decoder.encoding) {
707             Ok(name) => {
708                 if !decoder.var_names.contains_key(&name) {
709                     name
710                 } else {
711                     let new_name = decoder.generate_name();
712                     warn(Error::DuplicateVariableName {
713                         duplicate_name: name.clone(),
714                         new_name: new_name.clone(),
715                     });
716                     new_name
717                 }
718             }
719             Err(id_error) => {
720                 let new_name = decoder.generate_name();
721                 warn(Error::InvalidVariableName {
722                     id_error,
723                     new_name: new_name.clone(),
724                 });
725                 new_name
726             }
727         };
728         let variable = Variable {
729             dict_index: decoder.n_dict_indexes,
730             short_name: name.clone(),
731             long_name: None,
732             width,
733         };
734         decoder.n_dict_indexes += width.n_dict_indexes();
735         assert!(decoder
736             .var_names
737             .insert(name.clone(), variable.dict_index)
738             .is_none());
739         assert!(decoder
740             .variables
741             .insert(variable.dict_index, variable)
742             .is_none());
743
744         let print_format = decode_format(input.print_format, width, |new_spec, format_error| {
745             warn(Error::InvalidPrintFormat {
746                 new_spec,
747                 variable: name.clone(),
748                 format_error,
749             })
750         });
751         let write_format = decode_format(input.write_format, width, |new_spec, format_error| {
752             warn(Error::InvalidWriteFormat {
753                 new_spec,
754                 variable: name.clone(),
755                 format_error,
756             })
757         });
758         let label = input
759             .label
760             .as_ref()
761             .map(|label| decoder.decode_string(&label.0, &warn));
762         Ok(Some(VariableRecord {
763             width,
764             name,
765             print_format,
766             write_format,
767             missing_values: MissingValues::decode(decoder, &input.missing_values, warn),
768             label,
769         }))
770     }
771 }
772
773 #[derive(Clone, Debug)]
774 pub struct DocumentRecord(Vec<String>);
775
776 impl TryDecode for DocumentRecord {
777     type Input = crate::raw::DocumentRecord;
778
779     fn try_decode(
780         decoder: &mut Decoder,
781         input: &Self::Input,
782         warn: impl Fn(Error),
783     ) -> Result<Option<Self>, Error> {
784         Ok(Some(DocumentRecord(
785             input
786                 .lines
787                 .iter()
788                 .map(|s| trim_end_spaces(decoder.decode_string(&s.0, &warn)))
789                 .collect(),
790         )))
791     }
792 }
793
794 trait TextRecord
795 where
796     Self: Sized,
797 {
798     const NAME: &'static str;
799     fn parse(input: &str, warn: impl Fn(Error)) -> Result<Self, Error>;
800 }
801
802 #[derive(Clone, Debug)]
803 pub struct VariableSet {
804     pub name: String,
805     pub vars: Vec<String>,
806 }
807
808 impl VariableSet {
809     fn parse(input: &str) -> Result<Self, Error> {
810         let (name, input) = input.split_once('=').ok_or(Error::TBD)?;
811         let vars = input.split_ascii_whitespace().map(String::from).collect();
812         Ok(VariableSet {
813             name: name.into(),
814             vars,
815         })
816     }
817 }
818
819 trait WarnOnError<T> {
820     fn warn_on_error<F: Fn(Error)>(self, warn: &F) -> Option<T>;
821 }
822 impl<T> WarnOnError<T> for Result<T, Error> {
823     fn warn_on_error<F: Fn(Error)>(self, warn: &F) -> Option<T> {
824         match self {
825             Ok(result) => Some(result),
826             Err(error) => {
827                 warn(error);
828                 None
829             }
830         }
831     }
832 }
833
834 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
835 pub enum Value {
836     Number(Option<OrderedFloat<f64>>),
837     String(String),
838 }
839
840 impl Value {
841     pub fn decode(raw: &raw::Value, decoder: &Decoder) -> Self {
842         match raw {
843             raw::Value::Number(x) => Value::Number(x.map(|x| x.into())),
844             raw::Value::String(s) => Value::String(decoder.decode_exact_length(&s.0).into()),
845         }
846     }
847 }
848
849 #[derive(Clone, Debug)]
850 pub struct ValueLabel {
851     pub value: Value,
852     pub label: String,
853 }
854
855 #[derive(Clone, Debug)]
856 pub struct ValueLabelRecord {
857     pub var_type: VarType,
858     pub labels: Vec<ValueLabel>,
859     pub variables: Vec<Identifier>,
860 }
861
862 impl TryDecode for ValueLabelRecord {
863     type Input = crate::raw::ValueLabelRecord;
864     fn try_decode(
865         decoder: &mut Decoder,
866         input: &Self::Input,
867         warn: impl Fn(Error),
868     ) -> Result<Option<ValueLabelRecord>, Error> {
869         let variables: Vec<&Variable> = input
870             .dict_indexes
871             .iter()
872             .filter_map(|&dict_index| {
873                 decoder
874                     .get_var_by_index(dict_index as usize)
875                     .warn_on_error(&warn)
876             })
877             .filter(|&variable| match variable.width {
878                 VarWidth::String(width) if width > 8 => {
879                     warn(Error::InvalidLongStringValueLabel(
880                         variable.short_name.clone(),
881                     ));
882                     false
883                 }
884                 _ => true,
885             })
886             .collect();
887         let mut i = variables.iter();
888         let Some(&first_var) = i.next() else {
889             return Ok(None);
890         };
891         let var_type: VarType = first_var.width.into();
892         for &variable in i {
893             let this_type: VarType = variable.width.into();
894             if var_type != this_type {
895                 let (numeric_var, string_var) = match var_type {
896                     VarType::Numeric => (first_var, variable),
897                     VarType::String => (variable, first_var),
898                 };
899                 warn(Error::ValueLabelsDifferentTypes {
900                     numeric_var: numeric_var.short_name.clone(),
901                     string_var: string_var.short_name.clone(),
902                 });
903                 return Ok(None);
904             }
905         }
906         let labels = input
907             .labels
908             .iter()
909             .map(|(value, label)| {
910                 let label = decoder.decode_string(&label.0, &warn);
911                 let value = Value::decode(
912                     &raw::Value::from_raw(value, var_type, decoder.endian),
913                     decoder,
914                 );
915                 ValueLabel { value, label }
916             })
917             .collect();
918         let variables = variables
919             .iter()
920             .map(|&variable| variable.short_name.clone())
921             .collect();
922         Ok(Some(ValueLabelRecord {
923             var_type,
924             labels,
925             variables,
926         }))
927     }
928 }
929
930 #[derive(Clone, Debug)]
931 pub struct VariableSetRecord(Vec<VariableSet>);
932
933 impl TextRecord for VariableSetRecord {
934     const NAME: &'static str = "variable set";
935     fn parse(input: &str, warn: impl Fn(Error)) -> Result<Self, Error> {
936         let mut sets = Vec::new();
937         for line in input.lines() {
938             if let Some(set) = VariableSet::parse(line).warn_on_error(&warn) {
939                 sets.push(set)
940             }
941         }
942         Ok(VariableSetRecord(sets))
943     }
944 }
945
946 #[derive(Clone, Debug)]
947 pub struct ProductInfoRecord(pub String);
948
949 impl TextRecord for ProductInfoRecord {
950     const NAME: &'static str = "extra product info";
951     fn parse(input: &str, _warn: impl Fn(Error)) -> Result<Self, Error> {
952         Ok(ProductInfoRecord(input.into()))
953     }
954 }
955
956 #[derive(Clone, Debug)]
957 pub struct LongName {
958     pub short_name: Identifier,
959     pub long_name: Identifier,
960 }
961
962 impl LongName {
963     fn new(decoder: &mut Decoder, short_name: &str, long_name: &str) -> Result<LongName, Error> {
964         let short_name =
965             Identifier::new(short_name, decoder.encoding).map_err(Error::InvalidShortName)?;
966         let long_name =
967             Identifier::new(long_name, decoder.encoding).map_err(Error::InvalidLongName)?;
968         Ok(LongName {
969             short_name,
970             long_name,
971         })
972     }
973 }
974
975 #[derive(Clone, Debug)]
976 pub struct LongNameRecord(Vec<LongName>);
977
978 impl LongNameRecord {
979     pub fn parse(decoder: &mut Decoder, input: &str, warn: impl Fn(Error)) -> Result<Self, Error> {
980         let mut names = Vec::new();
981         for pair in input.split('\t').filter(|s| !s.is_empty()) {
982             if let Some((short_name, long_name)) = pair.split_once('=') {
983                 if let Some(long_name) =
984                     LongName::new(decoder, short_name, long_name).warn_on_error(&warn)
985                 {
986                     names.push(long_name);
987                 }
988             } else {
989                 warn(Error::TBD)
990             }
991         }
992         Ok(LongNameRecord(names))
993     }
994 }
995
996 #[derive(Clone, Debug)]
997 pub struct VeryLongString {
998     pub short_name: Identifier,
999     pub length: u16,
1000 }
1001
1002 impl VeryLongString {
1003     fn parse(decoder: &Decoder, input: &str) -> Result<VeryLongString, Error> {
1004         let Some((short_name, length)) = input.split_once('=') else {
1005             return Err(Error::TBD);
1006         };
1007         let short_name =
1008             Identifier::new(short_name, decoder.encoding).map_err(Error::InvalidLongStringName)?;
1009         let length: u16 = length.parse().map_err(|_| Error::TBD)?;
1010         if length > VarWidth::MAX_STRING {
1011             return Err(Error::TBD);
1012         }
1013         Ok(VeryLongString { short_name, length })
1014     }
1015 }
1016
1017 #[derive(Clone, Debug)]
1018 pub struct VeryLongStringRecord(Vec<VeryLongString>);
1019
1020 impl VeryLongStringRecord {
1021     pub fn parse(decoder: &Decoder, input: &str, warn: impl Fn(Error)) -> Result<Self, Error> {
1022         let mut very_long_strings = Vec::new();
1023         for tuple in input
1024             .split('\0')
1025             .map(|s| s.trim_end_matches('\t'))
1026             .filter(|s| !s.is_empty())
1027         {
1028             if let Some(vls) = VeryLongString::parse(decoder, tuple).warn_on_error(&warn) {
1029                 very_long_strings.push(vls)
1030             }
1031         }
1032         Ok(VeryLongStringRecord(very_long_strings))
1033     }
1034 }
1035
1036 #[derive(Clone, Debug)]
1037 pub struct Attribute {
1038     pub name: Identifier,
1039     pub values: Vec<String>,
1040 }
1041
1042 impl Attribute {
1043     fn parse<'a>(
1044         decoder: &Decoder,
1045         input: &'a str,
1046         warn: &impl Fn(Error),
1047     ) -> Result<(Option<Attribute>, &'a str), Error> {
1048         let Some((name, mut input)) = input.split_once('(') else {
1049             return Err(Error::TBD);
1050         };
1051         let mut values = Vec::new();
1052         loop {
1053             let Some((value, rest)) = input.split_once('\n') else {
1054                 return Err(Error::TBD);
1055             };
1056             if let Some(stripped) = value
1057                 .strip_prefix('\'')
1058                 .and_then(|value| value.strip_suffix('\''))
1059             {
1060                 values.push(stripped.into());
1061             } else {
1062                 warn(Error::TBD);
1063                 values.push(value.into());
1064             }
1065             if let Some(rest) = rest.strip_prefix(')') {
1066                 let attribute = Identifier::new(name, decoder.encoding)
1067                     .map_err(Error::InvalidAttributeName)
1068                     .warn_on_error(warn)
1069                     .map(|name| Attribute { name, values });
1070                 return Ok((attribute, rest));
1071             };
1072             input = rest;
1073         }
1074     }
1075 }
1076
1077 #[derive(Clone, Debug)]
1078 pub struct AttributeSet(pub Vec<Attribute>);
1079
1080 impl AttributeSet {
1081     fn parse<'a>(
1082         decoder: &Decoder,
1083         mut input: &'a str,
1084         sentinel: Option<char>,
1085         warn: &impl Fn(Error),
1086     ) -> Result<(AttributeSet, &'a str), Error> {
1087         let mut attributes = Vec::new();
1088         let rest = loop {
1089             match input.chars().next() {
1090                 None => break input,
1091                 c if c == sentinel => break &input[1..],
1092                 _ => {
1093                     let (attribute, rest) = Attribute::parse(decoder, input, &warn)?;
1094                     if let Some(attribute) = attribute {
1095                         attributes.push(attribute);
1096                     }
1097                     input = rest;
1098                 }
1099             }
1100         };
1101         Ok((AttributeSet(attributes), rest))
1102     }
1103 }
1104
1105 #[derive(Clone, Debug)]
1106 pub struct FileAttributeRecord(AttributeSet);
1107
1108 impl FileAttributeRecord {
1109     pub fn parse(decoder: &Decoder, input: &str, warn: impl Fn(Error)) -> Result<Self, Error> {
1110         let (set, rest) = AttributeSet::parse(decoder, input, None, &warn)?;
1111         if !rest.is_empty() {
1112             warn(Error::TBD);
1113         }
1114         Ok(FileAttributeRecord(set))
1115     }
1116 }
1117
1118 #[derive(Clone, Debug)]
1119 pub struct VarAttributeSet {
1120     pub long_var_name: Identifier,
1121     pub attributes: AttributeSet,
1122 }
1123
1124 impl VarAttributeSet {
1125     fn parse<'a>(
1126         decoder: &Decoder,
1127         input: &'a str,
1128         warn: &impl Fn(Error),
1129     ) -> Result<(Option<VarAttributeSet>, &'a str), Error> {
1130         let Some((long_var_name, rest)) = input.split_once(':') else {
1131             return Err(Error::TBD);
1132         };
1133         let (attributes, rest) = AttributeSet::parse(decoder, rest, Some('/'), warn)?;
1134         let var_attribute = Identifier::new(long_var_name, decoder.encoding)
1135             .map_err(Error::InvalidAttributeVariableName)
1136             .warn_on_error(warn)
1137             .map(|name| VarAttributeSet {
1138                 long_var_name: name,
1139                 attributes,
1140             });
1141         Ok((var_attribute, rest))
1142     }
1143 }
1144
1145 #[derive(Clone, Debug)]
1146 pub struct VariableAttributeRecord(Vec<VarAttributeSet>);
1147
1148 impl VariableAttributeRecord {
1149     pub fn parse(decoder: &Decoder, mut input: &str, warn: impl Fn(Error)) -> Result<Self, Error> {
1150         let mut var_attribute_sets = Vec::new();
1151         while !input.is_empty() {
1152             let Some((var_attribute, rest)) =
1153                 VarAttributeSet::parse(decoder, input, &warn).warn_on_error(&warn)
1154             else {
1155                 break;
1156             };
1157             if let Some(var_attribute) = var_attribute {
1158                 var_attribute_sets.push(var_attribute);
1159             }
1160             input = rest;
1161         }
1162         Ok(VariableAttributeRecord(var_attribute_sets))
1163     }
1164 }
1165
1166 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1167 pub enum Measure {
1168     Nominal,
1169     Ordinal,
1170     Scale,
1171 }
1172
1173 impl Measure {
1174     fn try_decode(source: u32) -> Result<Option<Measure>, Error> {
1175         match source {
1176             0 => Ok(None),
1177             1 => Ok(Some(Measure::Nominal)),
1178             2 => Ok(Some(Measure::Ordinal)),
1179             3 => Ok(Some(Measure::Scale)),
1180             _ => Err(Error::InvalidMeasurement(source)),
1181         }
1182     }
1183 }
1184
1185 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1186 pub enum Alignment {
1187     Left,
1188     Right,
1189     Center,
1190 }
1191
1192 impl Alignment {
1193     fn try_decode(source: u32) -> Result<Option<Alignment>, Error> {
1194         match source {
1195             0 => Ok(None),
1196             1 => Ok(Some(Alignment::Left)),
1197             2 => Ok(Some(Alignment::Right)),
1198             3 => Ok(Some(Alignment::Center)),
1199             _ => Err(Error::InvalidAlignment(source)),
1200         }
1201     }
1202 }
1203
1204 #[derive(Clone, Debug)]
1205 pub struct VarDisplay {
1206     pub measure: Option<Measure>,
1207     pub width: Option<u32>,
1208     pub alignment: Option<Alignment>,
1209 }
1210
1211 #[derive(Clone, Debug)]
1212 pub struct VarDisplayRecord(pub Vec<VarDisplay>);
1213
1214 impl TryDecode for VarDisplayRecord {
1215     type Input = raw::VarDisplayRecord;
1216     fn try_decode(
1217         decoder: &mut Decoder,
1218         input: &Self::Input,
1219         warn: impl Fn(Error),
1220     ) -> Result<Option<Self>, Error> {
1221         let n_vars = decoder.variables.len();
1222         let n_per_var = if input.0.len() == 3 * n_vars {
1223             3
1224         } else if input.0.len() == 2 * n_vars {
1225             2
1226         } else {
1227             return Err(Error::TBD);
1228         };
1229
1230         let var_displays = input
1231             .0
1232             .chunks(n_per_var)
1233             .map(|chunk| {
1234                 let (measure, width, alignment) = match n_per_var == 3 {
1235                     true => (chunk[0], Some(chunk[1]), chunk[2]),
1236                     false => (chunk[0], None, chunk[1]),
1237                 };
1238                 let measure = Measure::try_decode(measure).warn_on_error(&warn).flatten();
1239                 let alignment = Alignment::try_decode(alignment)
1240                     .warn_on_error(&warn)
1241                     .flatten();
1242                 VarDisplay {
1243                     measure,
1244                     width,
1245                     alignment,
1246                 }
1247             })
1248             .collect();
1249         Ok(Some(VarDisplayRecord(var_displays)))
1250     }
1251 }
1252
1253 #[derive(Clone, Debug)]
1254 pub enum MultipleResponseType {
1255     MultipleDichotomy {
1256         value: Value,
1257         labels: CategoryLabels,
1258     },
1259     MultipleCategory,
1260 }
1261
1262 impl MultipleResponseType {
1263     fn decode(
1264         decoder: &Decoder,
1265         mr_set: &Identifier,
1266         input: &raw::MultipleResponseType,
1267         min_width: VarWidth,
1268         warn: &impl Fn(Error),
1269     ) -> Result<Self, Error> {
1270         let mr_type = match input {
1271             raw::MultipleResponseType::MultipleDichotomy { value, labels } => {
1272                 let value = decoder.decode_string_cow(&value.0, warn);
1273                 let value = match min_width {
1274                     VarWidth::Numeric => {
1275                         let number: f64 = value.trim().parse().map_err(|_| {
1276                             Error::InvalidMDGroupCountedValue {
1277                                 mr_set: mr_set.clone(),
1278                                 number: value.into(),
1279                             }
1280                         })?;
1281                         Value::Number(Some(number.into()))
1282                     }
1283                     VarWidth::String(max_width) => {
1284                         let value = value.trim_end_matches(' ');
1285                         let width = value.len();
1286                         if width > max_width as usize {
1287                             return Err(Error::TooWideMDGroupCountedValue {
1288                                 mr_set: mr_set.clone(),
1289                                 value: value.into(),
1290                                 width,
1291                                 max_width,
1292                             });
1293                         };
1294                         Value::String(value.into())
1295                     }
1296                 };
1297                 MultipleResponseType::MultipleDichotomy {
1298                     value,
1299                     labels: *labels,
1300                 }
1301             }
1302             raw::MultipleResponseType::MultipleCategory => MultipleResponseType::MultipleCategory,
1303         };
1304         Ok(mr_type)
1305     }
1306 }
1307
1308 #[derive(Clone, Debug)]
1309 pub struct MultipleResponseSet {
1310     pub name: Identifier,
1311     pub min_width: VarWidth,
1312     pub max_width: VarWidth,
1313     pub label: String,
1314     pub mr_type: MultipleResponseType,
1315     pub dict_indexes: Vec<DictIndex>,
1316 }
1317
1318 impl MultipleResponseSet {
1319     fn decode(
1320         decoder: &Decoder,
1321         input: &raw::MultipleResponseSet,
1322         warn: &impl Fn(Error),
1323     ) -> Result<Self, Error> {
1324         let mr_set_name = decoder
1325             .decode_identifier(&input.name.0, warn)
1326             .map_err(Error::InvalidMrSetName)?;
1327
1328         let label = decoder.decode_string(&input.label.0, warn);
1329
1330         let mut dict_indexes = Vec::with_capacity(input.short_names.len());
1331         for short_name in input.short_names.iter() {
1332             let short_name = match decoder.decode_identifier(&short_name.0, warn) {
1333                 Ok(name) => name,
1334                 Err(error) => {
1335                     warn(Error::InvalidMrSetName(error));
1336                     continue;
1337                 }
1338             };
1339             let Some(&dict_index) = decoder.var_names.get(&short_name) else {
1340                 warn(Error::UnknownMrSetVariable {
1341                     mr_set: mr_set_name.clone(),
1342                     short_name: short_name.clone(),
1343                 });
1344                 continue;
1345             };
1346             dict_indexes.push(dict_index);
1347         }
1348
1349         match dict_indexes.len() {
1350             0 => return Err(Error::EmptyMrSet(mr_set_name)),
1351             1 => return Err(Error::OneVarMrSet(mr_set_name)),
1352             _ => (),
1353         }
1354
1355         let Some((Some(min_width), Some(max_width))) = dict_indexes
1356             .iter()
1357             .map(|dict_index| decoder.variables[dict_index].width)
1358             .map(|w| (Some(w), Some(w)))
1359             .reduce(|(na, wa), (nb, wb)| (VarWidth::narrower(na, nb), VarWidth::wider(wa, wb)))
1360         else {
1361             return Err(Error::MixedMrSet(mr_set_name));
1362         };
1363
1364         let mr_type =
1365             MultipleResponseType::decode(decoder, &mr_set_name, &input.mr_type, min_width, warn)?;
1366
1367         Ok(MultipleResponseSet {
1368             name: mr_set_name,
1369             min_width,
1370             max_width,
1371             label,
1372             mr_type,
1373             dict_indexes,
1374         })
1375     }
1376 }
1377
1378 #[derive(Clone, Debug)]
1379 pub struct MultipleResponseRecord(pub Vec<MultipleResponseSet>);
1380
1381 impl TryDecode for MultipleResponseRecord {
1382     type Input = raw::MultipleResponseRecord;
1383
1384     fn try_decode(
1385         decoder: &mut Decoder,
1386         input: &Self::Input,
1387         warn: impl Fn(Error),
1388     ) -> Result<Option<Self>, Error> {
1389         let mut sets = Vec::with_capacity(input.0.len());
1390         for set in &input.0 {
1391             match MultipleResponseSet::decode(decoder, set, &warn) {
1392                 Ok(set) => sets.push(set),
1393                 Err(error) => warn(error),
1394             }
1395         }
1396         Ok(Some(MultipleResponseRecord(sets)))
1397     }
1398 }
1399
1400 #[derive(Clone, Debug)]
1401 pub struct LongStringMissingValues {
1402     /// Variable name.
1403     pub var_name: Identifier,
1404
1405     /// Missing values.
1406     pub missing_values: MissingValues,
1407 }
1408
1409 impl LongStringMissingValues {
1410     fn decode(
1411         decoder: &Decoder,
1412         input: &raw::LongStringMissingValues,
1413         warn: &impl Fn(Error),
1414     ) -> Result<Self, Error> {
1415         let var_name = decoder.decode_string(&input.var_name.0, warn);
1416         let var_name = Identifier::new(var_name.trim_end(), decoder.encoding)
1417             .map_err(Error::InvalidLongStringValueLabelName)?;
1418
1419         let missing_values = MissingValues::decode(decoder, &input.missing_values, warn);
1420
1421         Ok(LongStringMissingValues {
1422             var_name,
1423             missing_values,
1424         })
1425     }
1426 }
1427
1428 #[derive(Clone, Debug)]
1429 pub struct LongStringMissingValuesRecord(Vec<LongStringMissingValues>);
1430
1431 impl TryDecode for LongStringMissingValuesRecord {
1432     type Input = raw::LongStringMissingValueRecord;
1433
1434     fn try_decode(
1435         decoder: &mut Decoder,
1436         input: &Self::Input,
1437         warn: impl Fn(Error),
1438     ) -> Result<Option<Self>, Error> {
1439         let mut labels = Vec::with_capacity(input.0.len());
1440         for label in &input.0 {
1441             match LongStringMissingValues::decode(decoder, label, &warn) {
1442                 Ok(set) => labels.push(set),
1443                 Err(error) => warn(error),
1444             }
1445         }
1446         Ok(Some(LongStringMissingValuesRecord(labels)))
1447     }
1448 }
1449
1450 #[derive(Clone, Debug)]
1451 pub struct LongStringValueLabels {
1452     pub var_name: Identifier,
1453     pub width: VarWidth,
1454     pub labels: Vec<ValueLabel>,
1455 }
1456
1457 impl LongStringValueLabels {
1458     fn decode(
1459         decoder: &Decoder,
1460         input: &raw::LongStringValueLabels,
1461         warn: &impl Fn(Error),
1462     ) -> Result<Self, Error> {
1463         let var_name = decoder.decode_string(&input.var_name.0, warn);
1464         let var_name = Identifier::new(var_name.trim_end(), decoder.encoding)
1465             .map_err(Error::InvalidLongStringValueLabelName)?;
1466
1467         let min_width = 9;
1468         let max_width = VarWidth::MAX_STRING;
1469         if input.width < 9 || input.width > max_width as u32 {
1470             return Err(Error::InvalidLongValueLabelWidth {
1471                 name: var_name,
1472                 width: input.width,
1473                 min_width,
1474                 max_width,
1475             });
1476         }
1477         let width = input.width as u16;
1478
1479         let mut labels = Vec::with_capacity(input.labels.len());
1480         for (value, label) in input.labels.iter() {
1481             let value = Value::String(decoder.decode_exact_length(&value.0).into());
1482             let label = decoder.decode_string(&label.0, warn);
1483             labels.push(ValueLabel { value, label });
1484         }
1485
1486         Ok(LongStringValueLabels {
1487             var_name,
1488             width: VarWidth::String(width),
1489             labels,
1490         })
1491     }
1492 }
1493
1494 #[derive(Clone, Debug)]
1495 pub struct LongStringValueLabelRecord(pub Vec<LongStringValueLabels>);
1496
1497 impl TryDecode for LongStringValueLabelRecord {
1498     type Input = raw::LongStringValueLabelRecord;
1499
1500     fn try_decode(
1501         decoder: &mut Decoder,
1502         input: &Self::Input,
1503         warn: impl Fn(Error),
1504     ) -> Result<Option<Self>, Error> {
1505         let mut labels = Vec::with_capacity(input.0.len());
1506         for label in &input.0 {
1507             match LongStringValueLabels::decode(decoder, label, &warn) {
1508                 Ok(set) => labels.push(set),
1509                 Err(error) => warn(error),
1510             }
1511         }
1512         Ok(Some(LongStringValueLabelRecord(labels)))
1513     }
1514 }
1515
1516 #[cfg(test)]
1517 mod test {
1518     use encoding_rs::WINDOWS_1252;
1519
1520     #[test]
1521     fn test() {
1522         let mut s = String::new();
1523         s.push(char::REPLACEMENT_CHARACTER);
1524         let encoded = WINDOWS_1252.encode(&s).0;
1525         let decoded = WINDOWS_1252.decode(&encoded[..]).0;
1526         println!("{:?}", decoded);
1527     }
1528
1529     #[test]
1530     fn test2() {
1531         let charset: Vec<u8> = (0..=255).collect();
1532         println!("{}", charset.len());
1533         let decoded = WINDOWS_1252.decode(&charset[..]).0;
1534         println!("{}", decoded.len());
1535         let encoded = WINDOWS_1252.encode(&decoded[..]).0;
1536         println!("{}", encoded.len());
1537         assert_eq!(&charset[..], &encoded[..]);
1538     }
1539 }