#[error("Attribute record missing quotations, in {0:?}.")]
AttributeMissingQuotes(String),
+ #[error("Compression bias is {0} instead of the usual values of 0 or 100.")]
+ UnexpectedBias(f64),
+
#[error("Details TBD (raw)")]
TBD,
}
reader: &mut R,
endian: Endian,
var_types: &VarTypes,
- warn: &dyn Fn(Warning),
+ warn: &mut dyn FnMut(Warning),
) -> Result<Option<Record>, Error>
where
R: Read + Seek,
}
}
- pub fn decode(self, decoder: &Decoder) -> Result<DecodedRecord, Error> {
+ pub fn decode(self, decoder: &mut Decoder) -> Result<DecodedRecord, Error> {
Ok(match self {
Record::Header(record) => record.decode(decoder),
Record::Variable(record) => record.decode(decoder),
pub fn encoding_from_headers(
headers: &Vec<Record>,
- warn: &impl Fn(Warning),
+ warn: &mut impl FnMut(Warning),
) -> Result<&'static Encoding, Error> {
let mut encoding_record = None;
let mut integer_info_record = None;
}
impl HeaderRecord<RawString> {
- fn read<R: Read + Seek>(r: &mut R) -> Result<Self, Error> {
+ fn read<R: Read + Seek>(r: &mut R, warn: &mut dyn FnMut(Warning)) -> Result<Self, Error> {
let start = r.stream_position()?;
let magic: [u8; 4] = read_bytes(r)?;
let n_cases = (n_cases < i32::MAX as u32 / 2).then_some(n_cases);
let bias: f64 = endian.parse(read_bytes(r)?);
+ if bias != 100.0 && bias != 0.0 {
+ warn(Warning::UnexpectedBias(bias));
+ }
let creation_date = RawString(read_vec(r, 9)?);
let creation_time = RawString(read_vec(r, 8)?);
})
}
- pub fn decode(self, decoder: &Decoder) -> DecodedRecord {
+ pub fn decode(self, decoder: &mut Decoder) -> DecodedRecord {
let eye_catcher = decoder.decode(&self.eye_catcher).to_string();
let file_label = decoder.decode(&self.file_label).to_string();
let creation_date = decoder.decode(&self.creation_date).to_string();
}
}
-pub struct Decoder {
+pub struct Decoder<'a> {
pub encoding: &'static Encoding,
- pub warn: Box<dyn Fn(Warning)>,
+ pub warn: Box<dyn FnMut(Warning) + 'a>,
}
-impl Decoder {
+impl<'de> Decoder<'de> {
pub fn new<F>(encoding: &'static Encoding, warn: F) -> Self
where
- F: Fn(Warning) + 'static,
+ F: FnMut(Warning) + 'de,
{
Self {
encoding,
warn: Box::new(warn),
}
}
- fn warn(&self, warning: Warning) {
+ fn warn(&mut self, warning: Warning) {
(self.warn)(warning)
}
- fn decode_slice<'a>(&self, input: &'a [u8]) -> Cow<'a, str> {
+ fn decode_slice<'a>(&mut self, input: &'a [u8]) -> Cow<'a, str> {
let (output, malformed) = self.encoding.decode_without_bom_handling(input);
if malformed {
self.warn(Warning::MalformedString {
output
}
- fn decode<'a>(&self, input: &'a RawString) -> Cow<'a, str> {
+ fn decode<'a>(&mut self, input: &'a RawString) -> Cow<'a, str> {
self.decode_slice(input.0.as_slice())
}
- pub fn decode_identifier(&self, input: &RawString) -> Result<Identifier, IdError> {
- self.new_identifier(&self.decode(input))
+ pub fn decode_identifier(&mut self, input: &RawString) -> Result<Identifier, IdError> {
+ let decoded = &self.decode(input);
+ self.new_identifier(decoded)
}
pub fn new_identifier(&self, name: &str) -> Result<Identifier, IdError> {
End,
}
-pub struct Reader<R>
+pub struct Reader<'a, R>
where
R: Read + Seek + 'static,
{
reader: Option<R>,
- warn: Box<dyn Fn(Warning)>,
+ warn: Box<dyn FnMut(Warning) + 'a>,
header: HeaderRecord<RawString>,
var_types: VarTypes,
state: ReaderState,
}
-impl<R> Reader<R>
+impl<'a, R> Reader<'a, R>
where
R: Read + Seek + 'static,
{
- pub fn new<F>(mut reader: R, warn: F) -> Result<Self, Error>
- where
- F: Fn(Warning) + 'static,
- {
- let header = HeaderRecord::read(&mut reader)?;
+ pub fn new(mut reader: R, mut warn: impl FnMut(Warning) + 'a) -> Result<Self, Error> {
+ let header = HeaderRecord::read(&mut reader, &mut warn)?;
Ok(Self {
reader: Some(reader),
warn: Box::new(warn),
self.reader.as_mut().unwrap(),
self.header.endian,
&self.var_types,
- &self.warn,
+ &mut self.warn,
) {
Ok(Some(record)) => break record,
Ok(None) => (),
}
}
-impl<R> Iterator for Reader<R>
+impl<'a, R> Iterator for Reader<'a, R>
where
R: Read + Seek + 'static,
{
raw_width: RawWidth,
code: i32,
endian: Endian,
- warn: &dyn Fn(Warning),
+ warn: &mut dyn FnMut(Warning),
) -> Result<Self, Error> {
let (individual_values, has_range) = match code {
0 => return Ok(Self::default()),
fn read<R: Read + Seek>(
r: &mut R,
endian: Endian,
- warn: &dyn Fn(Warning),
+ warn: &mut dyn FnMut(Warning),
) -> Result<Record, Error> {
let start_offset = r.stream_position()?;
let width: i32 = endian.parse(read_bytes(r)?);
}))
}
- pub fn decode(self, decoder: &Decoder) -> DecodedRecord {
+ pub fn decode(self, decoder: &mut Decoder) -> DecodedRecord {
DecodedRecord::Variable(VariableRecord {
offsets: self.offsets.clone(),
width: self.width,
r: &mut R,
endian: Endian,
var_types: &VarTypes,
- warn: &dyn Fn(Warning),
+ warn: &mut dyn FnMut(Warning),
) -> Result<Option<Record>, Error> {
let label_offset = r.stream_position()?;
let n: u32 = endian.parse(read_bytes(r)?);
})))
}
- fn decode(self, decoder: &Decoder) -> ValueLabelRecord<RawStrArray<8>, String> {
+ fn decode(self, decoder: &mut Decoder) -> ValueLabelRecord<RawStrArray<8>, String> {
let labels = self
.labels
.iter()
}
}
- pub fn decode(self, decoder: &Decoder) -> DecodedRecord {
+ pub fn decode(self, decoder: &mut Decoder) -> DecodedRecord {
DecodedRecord::Document(DocumentRecord {
offsets: self.offsets.clone(),
lines: self
fn decode(
&self,
- decoder: &Decoder,
+ decoder: &mut Decoder,
) -> Result<MultipleResponseSet<Identifier, String>, Warning> {
let mut short_names = Vec::with_capacity(self.short_names.len());
for short_name in self.short_names.iter() {
if let Some(short_name) = decoder
.decode_identifier(short_name)
.map_err(Warning::InvalidMrSetName)
- .issue_warning(&decoder.warn)
+ .issue_warning(&mut decoder.warn)
{
short_names.push(short_name);
}
}
impl MultipleResponseRecord<RawString, RawString> {
- fn decode(self, decoder: &Decoder) -> DecodedRecord {
+ fn decode(self, decoder: &mut Decoder) -> DecodedRecord {
let mut sets = Vec::new();
for set in self.0.iter() {
- if let Some(set) = set.decode(decoder).issue_warning(&decoder.warn) {
+ if let Some(set) = set.decode(decoder).issue_warning(&mut decoder.warn) {
sets.push(set);
}
}
ext: &Extension,
var_types: &VarTypes,
endian: Endian,
- warn: &dyn Fn(Warning),
+ warn: &mut dyn FnMut(Warning),
) -> Result<Record, Warning> {
if ext.size != 4 {
return Err(Warning::BadRecordSize {
let mut input = &ext.data[..];
for _ in 0..n_vars {
let measure = Measure::try_decode(endian.parse(read_bytes(&mut input).unwrap()))
- .issue_warning(&warn)
+ .issue_warning(warn)
.flatten();
let width = has_width.then(|| endian.parse(read_bytes(&mut input).unwrap()));
let alignment = Alignment::try_decode(endian.parse(read_bytes(&mut input).unwrap()))
- .issue_warning(&warn)
+ .issue_warning(warn)
.flatten();
var_displays.push(VarDisplay {
measure,
}
impl LongStringMissingValues<RawString> {
- fn decode(&self, decoder: &Decoder) -> Result<LongStringMissingValues<Identifier>, IdError> {
+ fn decode(
+ &self,
+ decoder: &mut Decoder,
+ ) -> Result<LongStringMissingValues<Identifier>, IdError> {
Ok(LongStringMissingValues {
var_name: decoder.decode_identifier(&self.var_name)?,
missing_values: self.missing_values.clone(),
}
impl LongStringMissingValueRecord<RawString> {
- pub fn decode(self, decoder: &Decoder) -> LongStringMissingValueRecord<Identifier> {
+ pub fn decode(self, decoder: &mut Decoder) -> LongStringMissingValueRecord<Identifier> {
let mut mvs = Vec::with_capacity(self.0.len());
for mv in self.0.iter() {
if let Some(mv) = mv
.decode(decoder)
.map_err(Warning::InvalidLongStringMissingValueVariableName)
- .issue_warning(&decoder.warn)
+ .issue_warning(&mut decoder.warn)
{
mvs.push(mv);
}
text: extension.data.into(),
}
}
- pub fn decode(self, decoder: &Decoder) -> DecodedRecord {
+ pub fn decode(self, decoder: &mut Decoder) -> DecodedRecord {
match self.rec_type {
TextRecordType::VariableSets => {
DecodedRecord::VariableSets(VariableSetRecord::decode(&self, decoder))
pub struct VeryLongStringsRecord(pub Vec<VeryLongString>);
impl VeryLongStringsRecord {
- fn decode(source: &TextRecord, decoder: &Decoder) -> Self {
+ fn decode(source: &TextRecord, decoder: &mut Decoder) -> Self {
let input = decoder.decode(&source.text);
let mut very_long_strings = Vec::new();
for tuple in input
.map(|s| s.trim_start_matches('\t'))
.filter(|s| !s.is_empty())
{
- if let Some(vls) = VeryLongString::parse(decoder, tuple).issue_warning(&decoder.warn) {
+ if let Some(vls) =
+ VeryLongString::parse(decoder, tuple).issue_warning(&mut decoder.warn)
+ {
very_long_strings.push(vls)
}
}
}
impl Attribute {
- fn parse<'a>(decoder: &Decoder, input: &'a str) -> Result<(Attribute, &'a str), Warning> {
+ fn parse<'a>(decoder: &mut Decoder, input: &'a str) -> Result<(Attribute, &'a str), Warning> {
let Some((name, mut input)) = input.split_once('(') else {
return Err(Warning::AttributeMissingLParen(input.into()));
};
impl Attributes {
fn parse<'a>(
- decoder: &Decoder,
+ decoder: &mut Decoder,
mut input: &'a str,
sentinel: Option<char>,
) -> Result<(Attributes, &'a str), Warning> {
pub struct FileAttributeRecord(pub Attributes);
impl FileAttributeRecord {
- fn decode(source: &TextRecord, decoder: &Decoder) -> Self {
+ fn decode(source: &TextRecord, decoder: &mut Decoder) -> Self {
let input = decoder.decode(&source.text);
- match Attributes::parse(decoder, &input, None).issue_warning(&decoder.warn) {
+ match Attributes::parse(decoder, &input, None).issue_warning(&mut decoder.warn) {
Some((set, rest)) => {
if !rest.is_empty() {
decoder.warn(Warning::TBD);
}
impl VarAttributes {
- fn parse<'a>(decoder: &Decoder, input: &'a str) -> Result<(VarAttributes, &'a str), Warning> {
+ fn parse<'a>(
+ decoder: &mut Decoder,
+ input: &'a str,
+ ) -> Result<(VarAttributes, &'a str), Warning> {
let Some((long_var_name, rest)) = input.split_once(':') else {
return Err(Warning::TBD);
};
pub struct VariableAttributeRecord(pub Vec<VarAttributes>);
impl VariableAttributeRecord {
- fn decode(source: &TextRecord, decoder: &Decoder) -> Self {
+ fn decode(source: &TextRecord, decoder: &mut Decoder) -> Self {
let decoded = decoder.decode(&source.text);
let mut input = decoded.as_ref();
let mut var_attribute_sets = Vec::new();
while !input.is_empty() {
let Some((var_attribute, rest)) =
- VarAttributes::parse(decoder, input).issue_warning(&decoder.warn)
+ VarAttributes::parse(decoder, input).issue_warning(&mut decoder.warn)
else {
break;
};
pub struct LongNamesRecord(pub Vec<LongName>);
impl LongNamesRecord {
- fn decode(source: &TextRecord, decoder: &Decoder) -> Self {
+ fn decode(source: &TextRecord, decoder: &mut Decoder) -> Self {
let input = decoder.decode(&source.text);
let mut names = Vec::new();
for pair in input.split('\t').filter(|s| !s.is_empty()) {
- if let Some(long_name) = LongName::parse(pair, decoder).issue_warning(&decoder.warn) {
+ if let Some(long_name) = LongName::parse(pair, decoder).issue_warning(&mut decoder.warn)
+ {
names.push(long_name);
}
}
pub struct ProductInfoRecord(pub String);
impl ProductInfoRecord {
- fn decode(source: &TextRecord, decoder: &Decoder) -> Self {
+ fn decode(source: &TextRecord, decoder: &mut Decoder) -> Self {
Self(decoder.decode(&source.text).into())
}
}
}
impl VariableSet {
- fn parse(input: &str, decoder: &Decoder) -> Result<Self, Warning> {
+ fn parse(input: &str, decoder: &mut Decoder) -> Result<Self, Warning> {
let (name, input) = input
.split_once('=')
.ok_or(Warning::VariableSetMissingEquals)?;
.new_identifier(var)
.and_then(Identifier::must_be_ordinary)
.map_err(Warning::InvalidVariableSetName)
- .issue_warning(&decoder.warn)
+ .issue_warning(&mut decoder.warn)
{
vars.push(identifier);
}
}
impl VariableSetRecord {
- fn decode(source: &TextRecord, decoder: &Decoder) -> VariableSetRecord {
+ fn decode(source: &TextRecord, decoder: &mut Decoder) -> VariableSetRecord {
let mut sets = Vec::new();
let input = decoder.decode(&source.text);
for line in input.lines() {
- if let Some(set) = VariableSet::parse(line, decoder).issue_warning(&decoder.warn) {
+ if let Some(set) = VariableSet::parse(line, decoder).issue_warning(&mut decoder.warn) {
sets.push(set)
}
}
}
trait IssueWarning<T> {
- fn issue_warning<F>(self, warn: &F) -> Option<T>
- where
- F: Fn(Warning);
+ fn issue_warning(self, warn: &mut dyn FnMut(Warning)) -> Option<T>;
}
impl<T> IssueWarning<T> for Result<T, Warning> {
- fn issue_warning<F>(self, warn: &F) -> Option<T>
- where
- F: Fn(Warning),
- {
+ fn issue_warning(self, warn: &mut dyn FnMut(Warning)) -> Option<T> {
match self {
Ok(result) => Some(result),
Err(error) => {
r: &mut R,
endian: Endian,
var_types: &VarTypes,
- warn: &dyn Fn(Warning),
+ warn: &mut dyn FnMut(Warning),
) -> Result<Option<Record>, Error> {
let subtype = endian.parse(read_bytes(r)?);
let header_offset = r.stream_position()?;
impl LongStringValueLabels<RawString, RawString> {
fn decode(
&self,
- decoder: &Decoder,
+ decoder: &mut Decoder,
) -> Result<LongStringValueLabels<Identifier, String>, Warning> {
let var_name = decoder.decode(&self.var_name);
let var_name = Identifier::from_encoding(var_name.trim_end(), decoder.encoding)
}
impl LongStringValueLabelRecord<RawString, RawString> {
- fn decode(self, decoder: &Decoder) -> LongStringValueLabelRecord<Identifier, String> {
+ fn decode(self, decoder: &mut Decoder) -> LongStringValueLabelRecord<Identifier, String> {
let mut labels = Vec::with_capacity(self.0.len());
for label in &self.0 {
match label.decode(decoder) {