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