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