use crate::endian::{Endian, Parse, ToBytes};
-use crate::Error;
+use crate::{CategoryLabels, Compression, Error};
use flate2::read::ZlibDecoder;
use num::Integer;
use self::state::State;
-#[derive(Copy, Clone, Debug)]
-pub enum Compression {
- Simple,
- ZLib,
-}
-
#[derive(Clone, Debug)]
pub enum Record {
Header(Header),
- Document(Document),
Variable(Variable),
ValueLabel(ValueLabel),
VarIndexes(VarIndexes),
+ Document(Document),
IntegerInfo(IntegerInfo),
FloatInfo(FloatInfo),
VariableSets(UnencodedString),
FileAttributes(UnencodedString),
VariableAttributes(UnencodedString),
TextExtension(TextExtension),
- Extension(Extension),
+ OtherExtension(Extension),
EndOfHeaders(u32),
ZHeader(ZHeader),
ZTrailer(ZTrailer),
if let Ok(s) = from_utf8(s) {
s.into()
} else {
- let s: String = s
- .iter()
- .map(|c| char::from(*c))
- .collect();
+ let s: String = s.iter().map(|c| char::from(*c)).collect();
s.into()
}
}
}
}
-fn format_name(type_: u32) -> &'static str {
+fn format_name(type_: u32) -> Cow<'static, str> {
match type_ {
1 => "A",
2 => "AHEX",
39 => "SDATE",
40 => "MTIME",
41 => "YMDHMS",
- _ => "(unknown)",
- }
+ _ => return format!("<unknown format {type_}>").into()
+ }.into()
}
#[derive(Clone)]
pub name: [u8; 8],
/// Print format.
- pub print_format: u32,
+ pub print_format: Format,
/// Write format.
- pub write_format: u32,
+ pub write_format: Format,
/// Missing values.
pub missing_values: MissingValues,
"long string continuation record"
}
)?;
- writeln!(f, "Print format: {:?}", Format(self.print_format))?;
- writeln!(f, "Write format: {:?}", Format(self.write_format))?;
+ writeln!(f, "Print format: {:?}", self.print_format)?;
+ writeln!(f, "Write format: {:?}", self.write_format)?;
writeln!(f, "Name: {:?}", FallbackEncoding(&self.name))?;
- writeln!(
- f,
- "Variable label: {:?}",
- self.label
- )?;
+ writeln!(f, "Variable label: {:?}", self.label)?;
writeln!(f, "Missing values: {:?}", self.missing_values)
}
}
let width: i32 = endian.parse(read_bytes(r)?);
let has_variable_label: u32 = endian.parse(read_bytes(r)?);
let missing_value_code: i32 = endian.parse(read_bytes(r)?);
- let print_format: u32 = endian.parse(read_bytes(r)?);
- let write_format: u32 = endian.parse(read_bytes(r)?);
+ let print_format = Format(endian.parse(read_bytes(r)?));
+ let write_format = Format(endian.parse(read_bytes(r)?));
let name: [u8; 8] = read_bytes(r)?;
let label = match has_variable_label {
let little = format!("{:?}", little);
let big: f64 = Endian::Big.parse(self.0);
let big = format!("{:?}", big);
- let number = if little.len() <= big.len() { little } else { big };
+ let number = if little.len() <= big.len() {
+ little
+ } else {
+ big
+ };
write!(f, "{number}")?;
let string = fallback_encode(&self.0);
- let string = string.split(|c: char| c == '\0' || c.is_control()).next().unwrap();
+ let string = string
+ .split(|c: char| c == '\0' || c.is_control())
+ .next()
+ .unwrap();
write!(f, "/\"{string}\"")?;
Ok(())
}
}
}
-#[derive(Clone, Debug)]
-pub enum CategoryLabels {
- VarLabels,
- CountedValues,
-}
#[derive(Clone, Debug)]
pub enum MultipleResponseType {
MultipleDichotomy {
Ok((string.into(), rest))
}
-pub struct ExtraProductInfo(String);
+pub struct ProductInfo(String);
-impl TextRecord for ExtraProductInfo {
+impl TextRecord for ProductInfo {
const NAME: &'static str = "extra product info";
fn parse(input: &str, _warn: impl Fn(Error)) -> Result<Self, Error> {
- Ok(ExtraProductInfo(input.into()))
+ Ok(ProductInfo(input.into()))
}
}
#[derive(Clone, Debug)]
-pub struct VarDisplayRecord(Vec<u32>);
+pub struct VarDisplayRecord(pub Vec<u32>);
impl ExtensionRecord for VarDisplayRecord {
const SUBTYPE: u32 = 11;
};
values.push(Value::String(value));
}
- let missing_values = MissingValues { values, range: None };
+ let missing_values = MissingValues {
+ values,
+ range: None,
+ };
missing_value_set.push(LongStringMissingValues {
var_name,
- missing_values
+ missing_values,
});
}
Ok(LongStringMissingValueSet(missing_value_set))
fn parse(ext: &Extension, _endian: Endian, _warn: impl Fn(Error)) -> Result<Self, Error> {
ext.check_size::<Self>()?;
- Ok(EncodingRecord(String::from_utf8(ext.data.clone()).map_err(
- |_| Error::BadEncodingName { offset: ext.offset },
- )?))
+ Ok(EncodingRecord(
+ String::from_utf8(ext.data.clone())
+ .map_err(|_| Error::BadEncodingName { offset: ext.offset })?,
+ ))
}
}
data,
};
match subtype {
- IntegerInfo::SUBTYPE => Ok(Record::IntegerInfo(IntegerInfo::parse(&extension, endian, |_| ())?)),
- FloatInfo::SUBTYPE => Ok(Record::FloatInfo(FloatInfo::parse(&extension, endian, |_| ())?)),
- VarDisplayRecord::SUBTYPE => Ok(Record::VarDisplay(VarDisplayRecord::parse(&extension, endian, |_| ())?)),
- MultipleResponseRecord::SUBTYPE | 19 => Ok(Record::MultipleResponse(MultipleResponseRecord::parse(&extension, endian, |_| ())?)),
- LongStringValueLabelRecord::SUBTYPE => Ok(Record::LongStringValueLabels(LongStringValueLabelRecord::parse(&extension, endian, |_| ())?)),
- EncodingRecord::SUBTYPE => Ok(Record::Encoding(EncodingRecord::parse(&extension, endian, |_| ())?)),
- NumberOfCasesRecord::SUBTYPE => Ok(Record::NumberOfCases(NumberOfCasesRecord::parse(&extension, endian, |_| ())?)),
- x if x == TextExtensionSubtype::VariableSets as u32 => Ok(Record::VariableSets(UnencodedString(extension.data))),
- x if x == TextExtensionSubtype::ProductInfo as u32 => Ok(Record::ProductInfo(UnencodedString(extension.data))),
- x if x == TextExtensionSubtype::LongNames as u32 => Ok(Record::LongNames(UnencodedString(extension.data))),
- x if x == TextExtensionSubtype::LongStrings as u32 => Ok(Record::LongStrings(UnencodedString(extension.data))),
- x if x == TextExtensionSubtype::FileAttributes as u32 => Ok(Record::FileAttributes(UnencodedString(extension.data))),
- x if x == TextExtensionSubtype::VariableAttributes as u32 => Ok(Record::VariableAttributes(UnencodedString(extension.data))),
- _ => Ok(Record::Extension(extension))
+ IntegerInfo::SUBTYPE => Ok(Record::IntegerInfo(IntegerInfo::parse(
+ &extension,
+ endian,
+ |_| (),
+ )?)),
+ FloatInfo::SUBTYPE => Ok(Record::FloatInfo(FloatInfo::parse(
+ &extension,
+ endian,
+ |_| (),
+ )?)),
+ VarDisplayRecord::SUBTYPE => Ok(Record::VarDisplay(VarDisplayRecord::parse(
+ &extension,
+ endian,
+ |_| (),
+ )?)),
+ MultipleResponseRecord::SUBTYPE | 19 => Ok(Record::MultipleResponse(
+ MultipleResponseRecord::parse(&extension, endian, |_| ())?,
+ )),
+ LongStringValueLabelRecord::SUBTYPE => Ok(Record::LongStringValueLabels(
+ LongStringValueLabelRecord::parse(&extension, endian, |_| ())?,
+ )),
+ EncodingRecord::SUBTYPE => Ok(Record::Encoding(EncodingRecord::parse(
+ &extension,
+ endian,
+ |_| (),
+ )?)),
+ NumberOfCasesRecord::SUBTYPE => Ok(Record::NumberOfCases(NumberOfCasesRecord::parse(
+ &extension,
+ endian,
+ |_| (),
+ )?)),
+ x if x == TextExtensionSubtype::VariableSets as u32 => {
+ Ok(Record::VariableSets(UnencodedString(extension.data)))
+ }
+ x if x == TextExtensionSubtype::ProductInfo as u32 => {
+ Ok(Record::ProductInfo(UnencodedString(extension.data)))
+ }
+ x if x == TextExtensionSubtype::LongNames as u32 => {
+ Ok(Record::LongNames(UnencodedString(extension.data)))
+ }
+ x if x == TextExtensionSubtype::LongStrings as u32 => {
+ Ok(Record::LongStrings(UnencodedString(extension.data)))
+ }
+ x if x == TextExtensionSubtype::FileAttributes as u32 => {
+ Ok(Record::FileAttributes(UnencodedString(extension.data)))
+ }
+ x if x == TextExtensionSubtype::VariableAttributes as u32 => {
+ Ok(Record::VariableAttributes(UnencodedString(extension.data)))
+ }
+ _ => Ok(Record::OtherExtension(extension)),
}
}
}