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