use encoding_rs::Encoding;
use crate::{
- format::Spec,
- identifier::{Identifier, Error as IdError},
- {endian::Endian, CategoryLabels, Compression},
+ format::{Spec, UncheckedSpec, Width},
+ identifier::{Error as IdError, Identifier},
+ {endian::Endian, CategoryLabels, Compression}, raw,
};
use thiserror::Error as ThisError;
}
impl Decoder {
- fn take_name(&mut self, id: Identifier) -> bool {
- self.var_names.insert(id)
+ fn take_name(&mut self, id: &Identifier) -> bool {
+ self.var_names.insert(id.clone())
}
fn generate_name(&mut self) -> Identifier {
loop {
self.n_generated_names += 1;
- let name = Identifier::new(&format!("VAR{:03}", self.n_generated_names), self.encoding).unwrap();
- if self.take_name(name.clone()) {
+ let name = Identifier::new(&format!("VAR{:03}", self.n_generated_names), self.encoding)
+ .unwrap();
+ if self.take_name(&name) {
return name;
}
assert!(self.n_generated_names < usize::MAX);
type Input = crate::raw::Header;
fn decode(decoder: &Decoder, input: &Self::Input, warn: impl Fn(Error)) -> Result<Self, Error> {
- let eye_catcher = decoder.decode_string(&input.eye_catcher, &warn);
- let file_label = decoder.decode_string(&input.file_label, &warn);
- let creation_date = decoder.decode_string(&input.creation_date, &warn);
+ let eye_catcher = decoder.decode_string(&input.eye_catcher.0, &warn);
+ let file_label = decoder.decode_string(&input.file_label.0, &warn);
+ let creation_date = decoder.decode_string(&input.creation_date.0, &warn);
let creation_date = NaiveDate::parse_from_str(&creation_date, "%v").unwrap_or_else(|_| {
warn(Error::InvalidCreationDate {
creation_date: creation_date.into(),
});
Default::default()
});
- let creation_time = decoder.decode_string(&input.creation_time, &warn);
+ let creation_time = decoder.decode_string(&input.creation_time.0, &warn);
let creation_time =
NaiveTime::parse_from_str(&creation_time, "%H:%M:%S").unwrap_or_else(|_| {
warn(Error::InvalidCreationTime {
}
pub struct Variable {
- pub width: i32,
+ pub width: Width,
pub name: Identifier,
pub print_format: Spec,
pub write_format: Spec,
+ //pub missing_values: MissingValues,
+ pub label: Option<String>,
+}
+
+fn decode_format(raw: raw::Spec, name: &str, width: Width) -> Spec {
+ UncheckedSpec::try_from(raw)
+ .and_then(Spec::try_from)
+ .and_then(|x| x.check_width_compatibility(Some(name), width))
+ .unwrap_or_else(|_warning| {
+ /*warn(warning);*/
+ Spec::default_for_width(width)
+ })
}
fn decode_var(
})
}
};
- let name = decoder.decode_string(&input.name, &warn);
+ let width = input.width as Width;
+ let name = decoder.decode_string(&input.name.0, &warn);
let name = match Identifier::new(&name, decoder.encoding) {
Ok(name) => {
- if !decoder.take_name(name) {
+ if !decoder.take_name(&name) {
decoder.generate_name()
} else {
name
decoder.generate_name()
}
};
+ let print_format = decode_format(input.print_format, &name.0, width);
+ let write_format = decode_format(input.write_format, &name.0, width);
+ let label = input.label.as_ref().map(|label| decoder.decode_string(&label.0, &warn).into());
+ Ok(Some(Variable { width, name, print_format, write_format, label }))
}
#[derive(Clone)]
input
.lines
.iter()
- .map(|s| decoder.decode_string(s, &warn).into())
+ .map(|s| decoder.decode_string(&s.0, &warn).into())
.collect(),
))
}