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