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