#[error("Invalid ZSAV compression code {0}")]
InvalidZsavCompression(u32),
- #[error("Variable record at offset {offset:#x} specifies width {width} not in valid range [-1,255).")]
- BadVariableWidth { offset: u64, width: i32 },
-
#[error("Document record at offset {offset:#x} has document line count ({n}) greater than the maximum number {max}.")]
BadDocumentLength { offset: u64, n: usize, max: usize },
#[error("At offset {offset:#x}, number of variables indexes for value labels ({n}) is greater than the maximum number ({max}).")]
TooManyVarIndexes { offset: u64, n: u32, max: u32 },
- #[error("At offset {offset:#x}, at least one valid variable index for value labels is required but none were specified.")]
- NoVarIndexes { offset: u64 },
-
- #[error("At offset {offset:#x}, the first variable index is for a {var_type} variable but the following variable indexes are for {} variables: {wrong_types:?}", var_type.opposite())]
- MixedVarTypes {
- offset: u64,
- var_type: VarType,
- wrong_types: Vec<u32>,
- },
-
- #[error("At offset {offset:#x}, one or more variable indexes for value labels were not in the valid range [1,{max}]: {invalid:?}")]
- InvalidVarIndexes {
- offset: u64,
- max: usize,
- invalid: Vec<u32>,
- },
-
#[error("At offset {offset:#x}, record type 7 subtype {subtype} is too large with element size {size} and {count} elements.")]
ExtensionRecordTooLarge {
offset: u64,
expected_n_blocks: u64,
ztrailer_len: u64,
},
+}
+
+#[derive(ThisError, Debug)]
+pub enum Warning {
+ #[error("Unexpected end of data inside extension record.")]
+ UnexpectedEndOfData,
+
+ #[error("At offset {offset:#x}, at least one valid variable index for value labels is required but none were specified.")]
+ NoVarIndexes { offset: u64 },
+
+ #[error("At offset {offset:#x}, the first variable index is for a {var_type} variable but the following variable indexes are for {} variables: {wrong_types:?}", var_type.opposite())]
+ MixedVarTypes {
+ offset: u64,
+ var_type: VarType,
+ wrong_types: Vec<u32>,
+ },
+
+ #[error("At offset {offset:#x}, one or more variable indexes for value labels were not in the valid range [1,{max}]: {invalid:?}")]
+ InvalidVarIndexes {
+ offset: u64,
+ max: usize,
+ invalid: Vec<u32>,
+ },
#[error("At offset {offset:#x}, {record} has bad size {size} bytes instead of the expected {expected_size}.")]
BadRecordSize {
TBD,
}
+impl From<IoError> for Warning {
+ fn from(_source: IoError) -> Self {
+ Self::UnexpectedEndOfData
+ }
+}
+
#[derive(Clone, Debug)]
pub enum Record {
Header(HeaderRecord<RawString>),
reader: &mut R,
endian: Endian,
var_types: &[VarType],
- warn: &Box<dyn Fn(Error)>,
+ warn: &Box<dyn Fn(Warning)>,
) -> Result<Option<Record>, Error>
where
R: Read + Seek,
}
}
- fn decode<'a>(&'a self, decoder: &Decoder) -> Result<DecodedRecord<'a>, Error> {
+ pub fn decode<'a>(&'a self, decoder: &Decoder) -> Result<DecodedRecord<'a>, Error> {
Ok(match self {
Record::Header(record) => record.decode(decoder),
Record::Variable(record) => record.decode(decoder),
Record::VarDisplay(record) => DecodedRecord::VarDisplay(record.clone()),
Record::MultipleResponse(record) => record.decode(decoder),
Record::LongStringValueLabels(record) => {
- DecodedRecord::LongStringValueLabels(record.decode(decoder)?)
+ DecodedRecord::LongStringValueLabels(record.decode(decoder))
}
Record::LongStringMissingValues(record) => {
DecodedRecord::LongStringMissingValues(record.decode(decoder))
}
Record::Encoding(record) => DecodedRecord::Encoding(record.clone()),
Record::NumberOfCases(record) => DecodedRecord::NumberOfCases(record.clone()),
- Record::Text(record) => record.decode(decoder)?,
+ Record::Text(record) => record.decode(decoder),
Record::OtherExtension(record) => DecodedRecord::OtherExtension(record.clone()),
Record::EndOfHeaders(record) => DecodedRecord::EndOfHeaders(record.clone()),
Record::ZHeader(record) => DecodedRecord::ZHeader(record.clone()),
pub struct Decoder {
pub encoding: &'static Encoding,
- pub warn: Box<dyn Fn(Error)>,
+ pub warn: Box<dyn Fn(Warning)>,
}
impl Decoder {
- fn warn(&self, error: Error) {
- (self.warn)(error)
+ fn warn(&self, warning: Warning) {
+ (self.warn)(warning)
}
fn decode_slice<'a>(&self, input: &'a [u8]) -> Cow<'a, str> {
let (output, malformed) = self.encoding.decode_without_bom_handling(input);
if malformed {
- self.warn(Error::MalformedString {
+ self.warn(Warning::MalformedString {
encoding: self.encoding.name().into(),
text: output.clone().into(),
});
R: Read + Seek + 'static,
{
reader: Option<R>,
- warn: Box<dyn Fn(Error)>,
+ warn: Box<dyn Fn(Warning)>,
header: HeaderRecord<RawString>,
var_types: Vec<VarType>,
{
pub fn new<F>(mut reader: R, warn: F) -> Result<Self, Error>
where
- F: Fn(Error) + 'static,
+ F: Fn(Warning) + 'static,
{
let header = HeaderRecord::read(&mut reader)?;
Ok(Self {
r: &mut R,
endian: Endian,
var_types: &[VarType],
- warn: &Box<dyn Fn(Error)>,
+ warn: &Box<dyn Fn(Warning)>,
) -> Result<Option<Record>, Error> {
let label_offset = r.stream_position()?;
let n: u32 = endian.parse(read_bytes(r)?);
}
}
if !invalid_indexes.is_empty() {
- warn(Error::InvalidVarIndexes {
+ warn(Warning::InvalidVarIndexes {
offset: index_offset,
max: var_types.len(),
invalid: invalid_indexes,
}
let Some(&first_index) = dict_indexes.first() else {
- warn(Error::NoVarIndexes {
+ warn(Warning::NoVarIndexes {
offset: index_offset,
});
return Ok(None);
}
});
if !wrong_type_indexes.is_empty() {
- warn(Error::MixedVarTypes {
+ warn(Warning::MixedVarTypes {
offset: index_offset,
var_type,
wrong_types: wrong_type_indexes,
const SIZE: Option<u32>;
const COUNT: Option<u32>;
const NAME: &'static str;
- fn parse(ext: &Extension, endian: Endian) -> Result<Record, Error>;
+ fn parse(ext: &Extension, endian: Endian) -> Result<Record, Warning>;
}
#[derive(Clone, Debug)]
const COUNT: Option<u32> = Some(8);
const NAME: &'static str = "integer record";
- fn parse(ext: &Extension, endian: Endian) -> Result<Record, Error> {
+ fn parse(ext: &Extension, endian: Endian) -> Result<Record, Warning> {
ext.check_size::<Self>()?;
let mut input = &ext.data[..];
const COUNT: Option<u32> = Some(3);
const NAME: &'static str = "floating point record";
- fn parse(ext: &Extension, endian: Endian) -> Result<Record, Error> {
+ fn parse(ext: &Extension, endian: Endian) -> Result<Record, Warning> {
ext.check_size::<Self>()?;
let mut input = &ext.data[..];
}
impl MultipleResponseType {
- fn parse(input: &[u8]) -> Result<(MultipleResponseType, &[u8]), Error> {
+ fn parse(input: &[u8]) -> Result<(MultipleResponseType, &[u8]), Warning> {
let (mr_type, input) = match input.split_first() {
Some((b'C', input)) => (MultipleResponseType::MultipleCategory, input),
Some((b'D', input)) => {
} else if let Some(rest) = input.strip_prefix(b" 11 ") {
(CategoryLabels::VarLabels, rest)
} else {
- return Err(Error::TBD);
+ return Err(Warning::TBD);
};
let (value, input) = parse_counted_string(input)?;
(
input,
)
}
- _ => return Err(Error::TBD),
+ _ => return Err(Warning::TBD),
};
Ok((mr_type, input))
}
}
impl MultipleResponseSet<RawString, RawString> {
- fn parse(input: &[u8]) -> Result<(Self, &[u8]), Error> {
+ fn parse(input: &[u8]) -> Result<(Self, &[u8]), Warning> {
let Some(equals) = input.iter().position(|&b| b == b'=') else {
- return Err(Error::TBD);
+ return Err(Warning::TBD);
};
let (name, input) = input.split_at(equals);
let (mr_type, input) = MultipleResponseType::parse(input)?;
let Some(input) = input.strip_prefix(b" ") else {
- return Err(Error::TBD);
+ return Err(Warning::TBD);
};
let (label, mut input) = parse_counted_string(input)?;
let mut vars = Vec::new();
match input.split_first() {
Some((b' ', rest)) => {
let Some(length) = rest.iter().position(|b| b" \n".contains(b)) else {
- return Err(Error::TBD);
+ return Err(Warning::TBD);
};
let (var, rest) = rest.split_at(length);
if !var.is_empty() {
}
input = rest;
}
- _ => return Err(Error::TBD),
+ _ => return Err(Warning::TBD),
}
}
while input.first() == Some(&b'\n') {
fn decode<'a>(
&'a self,
decoder: &Decoder,
- ) -> Result<MultipleResponseSet<Identifier, Cow<'a, str>>, Error> {
+ ) -> Result<MultipleResponseSet<Identifier, Cow<'a, str>>, 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(|err| Error::InvalidMrSetName(err))
- .warn_on_error(&decoder.warn)
+ .map_err(|err| Warning::InvalidMrSetName(err))
+ .issue_warning(&decoder.warn)
{
short_names.push(short_name);
}
Ok(MultipleResponseSet {
name: decoder
.decode_identifier(&self.name)
- .map_err(|err| Error::InvalidMrSetVariableName(err))?,
+ .map_err(|err| Warning::InvalidMrSetVariableName(err))?,
label: decoder.decode(&self.label),
mr_type: self.mr_type.clone(),
short_names: short_names,
const COUNT: Option<u32> = None;
const NAME: &'static str = "multiple response set record";
- fn parse(ext: &Extension, _endian: Endian) -> Result<Record, Error> {
+ fn parse(ext: &Extension, _endian: Endian) -> Result<Record, Warning> {
ext.check_size::<Self>()?;
let mut input = &ext.data[..];
fn decode<'a>(&'a self, decoder: &Decoder) -> DecodedRecord {
let mut sets = Vec::new();
for set in self.0.iter() {
- if let Some(set) = set.decode(decoder).warn_on_error(&decoder.warn) {
+ if let Some(set) = set.decode(decoder).issue_warning(&decoder.warn) {
sets.push(set);
}
}
}
}
-fn parse_counted_string(input: &[u8]) -> Result<(RawString, &[u8]), Error> {
+fn parse_counted_string(input: &[u8]) -> Result<(RawString, &[u8]), Warning> {
let Some(space) = input.iter().position(|&b| b == b' ') else {
- return Err(Error::TBD);
+ return Err(Warning::TBD);
};
let Ok(length) = from_utf8(&input[..space]) else {
- return Err(Error::TBD);
+ return Err(Warning::TBD);
};
let Ok(length): Result<usize, _> = length.parse() else {
- return Err(Error::TBD);
+ return Err(Warning::TBD);
};
let input = &input[space + 1..];
if input.len() < length {
- return Err(Error::TBD);
+ return Err(Warning::TBD);
};
let (string, rest) = input.split_at(length);
}
}
- fn try_decode(source: u32) -> Result<Option<Measure>, Error> {
+ fn try_decode(source: u32) -> Result<Option<Measure>, Warning> {
match source {
0 => Ok(None),
1 => Ok(Some(Measure::Nominal)),
2 => Ok(Some(Measure::Ordinal)),
3 => Ok(Some(Measure::Scale)),
- _ => Err(Error::InvalidMeasurement(source)),
+ _ => Err(Warning::InvalidMeasurement(source)),
}
}
}
}
impl Alignment {
- fn try_decode(source: u32) -> Result<Option<Alignment>, Error> {
+ fn try_decode(source: u32) -> Result<Option<Alignment>, Warning> {
match source {
0 => Ok(None),
1 => Ok(Some(Alignment::Left)),
2 => Ok(Some(Alignment::Right)),
3 => Ok(Some(Alignment::Center)),
- _ => Err(Error::InvalidAlignment(source)),
+ _ => Err(Warning::InvalidAlignment(source)),
}
}
ext: &Extension,
n_vars: usize,
endian: Endian,
- warn: &Box<dyn Fn(Error)>,
- ) -> Result<Record, Error> {
+ warn: &Box<dyn Fn(Warning)>,
+ ) -> Result<Record, Warning> {
if ext.size != 4 {
- return Err(Error::BadRecordSize {
+ return Err(Warning::BadRecordSize {
offset: ext.offsets.start,
record: String::from("variable display record"),
size: ext.size,
} else if ext.count as usize == 2 * n_vars {
false
} else {
- return Err(Error::TBD);
+ return Err(Warning::TBD);
};
let mut var_displays = Vec::new();
let mut input = &ext.data[..];
for _ in 0..n_vars {
let measure = Measure::try_decode(endian.parse(read_bytes(&mut input).unwrap()))
- .warn_on_error(&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()))
- .warn_on_error(&warn)
+ .issue_warning(&warn)
.flatten();
var_displays.push(VarDisplay {
measure,
const COUNT: Option<u32> = None;
const NAME: &'static str = "long string missing values record";
- fn parse(ext: &Extension, endian: Endian) -> Result<Record, Error> {
+ fn parse(ext: &Extension, endian: Endian) -> Result<Record, Warning> {
ext.check_size::<Self>()?;
let mut input = &ext.data[..];
let value_len: u32 = endian.parse(read_bytes(&mut input)?);
if value_len != 8 {
let offset = (ext.data.len() - input.len() - 8) as u64 + ext.offsets.start;
- return Err(Error::BadLongMissingValueLength {
+ return Err(Warning::BadLongMissingValueLength {
record_offset: ext.offsets.start,
offset,
value_len,
for mv in self.0.iter() {
if let Some(mv) = mv
.decode(decoder)
- .map_err(|err| Error::InvalidLongStringMissingValueVariableName(err))
- .warn_on_error(&decoder.warn)
+ .map_err(|err| Warning::InvalidLongStringMissingValueVariableName(err))
+ .issue_warning(&decoder.warn)
{
mvs.push(mv);
}
const COUNT: Option<u32> = None;
const NAME: &'static str = "encoding record";
- fn parse(ext: &Extension, _endian: Endian) -> Result<Record, Error> {
+ fn parse(ext: &Extension, _endian: Endian) -> Result<Record, Warning> {
ext.check_size::<Self>()?;
Ok(Record::Encoding(EncodingRecord(
- String::from_utf8(ext.data.clone()).map_err(|_| Error::BadEncodingName {
+ String::from_utf8(ext.data.clone()).map_err(|_| Warning::BadEncodingName {
offset: ext.offsets.start,
})?,
)))
const COUNT: Option<u32> = Some(2);
const NAME: &'static str = "extended number of cases record";
- fn parse(ext: &Extension, endian: Endian) -> Result<Record, Error> {
+ fn parse(ext: &Extension, endian: Endian) -> Result<Record, Warning> {
ext.check_size::<Self>()?;
let mut input = &ext.data[..];
text: extension.data.into(),
}
}
- pub fn decode<'a>(&self, decoder: &Decoder) -> Result<DecodedRecord, Error> {
+ pub fn decode<'a>(&self, decoder: &Decoder) -> DecodedRecord {
match self.rec_type {
- TextRecordType::VariableSets => Ok(DecodedRecord::VariableSets(
- VariableSetRecord::decode(self, decoder),
- )),
- TextRecordType::ProductInfo => Ok(DecodedRecord::ProductInfo(
- ProductInfoRecord::decode(self, decoder),
- )),
- TextRecordType::LongNames => Ok(DecodedRecord::LongNames(LongNamesRecord::decode(
- self, decoder,
- ))),
- TextRecordType::VeryLongStrings => Ok(DecodedRecord::VeryLongStrings(
- VeryLongStringsRecord::decode(self, decoder),
- )),
- TextRecordType::FileAttributes => Ok(DecodedRecord::FileAttributes(
- FileAttributeRecord::decode(self, decoder),
- )),
- TextRecordType::VariableAttributes => Ok(DecodedRecord::VariableAttributes(
- VariableAttributeRecord::decode(self, decoder),
- )),
+ TextRecordType::VariableSets => {
+ DecodedRecord::VariableSets(VariableSetRecord::decode(self, decoder))
+ }
+ TextRecordType::ProductInfo => {
+ DecodedRecord::ProductInfo(ProductInfoRecord::decode(self, decoder))
+ }
+ TextRecordType::LongNames => {
+ DecodedRecord::LongNames(LongNamesRecord::decode(self, decoder))
+ }
+ TextRecordType::VeryLongStrings => {
+ DecodedRecord::VeryLongStrings(VeryLongStringsRecord::decode(self, decoder))
+ }
+ TextRecordType::FileAttributes => {
+ DecodedRecord::FileAttributes(FileAttributeRecord::decode(self, decoder))
+ }
+ TextRecordType::VariableAttributes => {
+ DecodedRecord::VariableAttributes(VariableAttributeRecord::decode(self, decoder))
+ }
}
}
}
}
impl VeryLongString {
- fn parse(decoder: &Decoder, input: &str) -> Result<VeryLongString, Error> {
+ fn parse(decoder: &Decoder, input: &str) -> Result<VeryLongString, Warning> {
let Some((short_name, length)) = input.split_once('=') else {
- return Err(Error::TBD);
+ return Err(Warning::TBD);
};
let short_name = decoder
.new_identifier(short_name)
- .map_err(Error::InvalidLongStringName)?;
- let length = length.parse().map_err(|_| Error::TBD)?;
+ .map_err(Warning::InvalidLongStringName)?;
+ let length = length.parse().map_err(|_| Warning::TBD)?;
Ok(VeryLongString { short_name, length })
}
}
.map(|s| s.trim_end_matches('\t'))
.filter(|s| !s.is_empty())
{
- if let Some(vls) = VeryLongString::parse(decoder, tuple).warn_on_error(&decoder.warn) {
+ if let Some(vls) = VeryLongString::parse(decoder, tuple).issue_warning(&decoder.warn) {
very_long_strings.push(vls)
}
}
}
impl Attribute {
- fn parse<'a>(decoder: &Decoder, input: &'a str) -> Result<(Attribute, &'a str), Error> {
+ fn parse<'a>(decoder: &Decoder, input: &'a str) -> Result<(Attribute, &'a str), Warning> {
let Some((name, mut input)) = input.split_once('(') else {
- return Err(Error::TBD);
+ return Err(Warning::TBD);
};
let name = decoder
.new_identifier(name)
- .map_err(Error::InvalidAttributeName)?;
+ .map_err(Warning::InvalidAttributeName)?;
let mut values = Vec::new();
loop {
let Some((value, rest)) = input.split_once('\n') else {
- return Err(Error::TBD);
+ return Err(Warning::TBD);
};
if let Some(stripped) = value
.strip_prefix('\'')
{
values.push(stripped.into());
} else {
- decoder.warn(Error::TBD);
+ decoder.warn(Warning::TBD);
values.push(value.into());
}
if let Some(rest) = rest.strip_prefix(')') {
decoder: &Decoder,
mut input: &'a str,
sentinel: Option<char>,
- ) -> Result<(AttributeSet, &'a str), Error> {
+ ) -> Result<(AttributeSet, &'a str), Warning> {
let mut attributes = HashMap::new();
let rest = loop {
match input.chars().next() {
impl FileAttributeRecord {
fn decode(source: &TextRecord, decoder: &Decoder) -> Self {
let input = decoder.decode(&source.text);
- match AttributeSet::parse(decoder, &input, None).warn_on_error(&decoder.warn) {
+ match AttributeSet::parse(decoder, &input, None).issue_warning(&decoder.warn) {
Some((set, rest)) => {
if !rest.is_empty() {
- decoder.warn(Error::TBD);
+ decoder.warn(Warning::TBD);
}
FileAttributeRecord(set)
}
}
impl VarAttributeSet {
- fn parse<'a>(decoder: &Decoder, input: &'a str) -> Result<(VarAttributeSet, &'a str), Error> {
+ fn parse<'a>(decoder: &Decoder, input: &'a str) -> Result<(VarAttributeSet, &'a str), Warning> {
let Some((long_var_name, rest)) = input.split_once(':') else {
- return Err(Error::TBD);
+ return Err(Warning::TBD);
};
let long_var_name = decoder
.new_identifier(long_var_name)
- .map_err(Error::InvalidAttributeVariableName)?;
+ .map_err(Warning::InvalidAttributeVariableName)?;
let (attributes, rest) = AttributeSet::parse(decoder, rest, Some('/'))?;
let var_attribute = VarAttributeSet {
long_var_name,
let mut var_attribute_sets = Vec::new();
while !input.is_empty() {
let Some((var_attribute, rest)) =
- VarAttributeSet::parse(decoder, &input).warn_on_error(&decoder.warn)
+ VarAttributeSet::parse(decoder, &input).issue_warning(&decoder.warn)
else {
break;
};
}
impl LongName {
- fn parse(input: &str, decoder: &Decoder) -> Result<Self, Error> {
+ fn parse(input: &str, decoder: &Decoder) -> Result<Self, Warning> {
let Some((short_name, long_name)) = input.split_once('=') else {
- return Err(Error::TBD);
+ return Err(Warning::TBD);
};
let short_name = decoder
.new_identifier(short_name)
- .map_err(Error::InvalidShortName)?;
+ .map_err(Warning::InvalidShortName)?;
let long_name = decoder
.new_identifier(long_name)
- .map_err(Error::InvalidLongName)?;
+ .map_err(Warning::InvalidLongName)?;
Ok(LongName {
short_name,
long_name,
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).warn_on_error(&decoder.warn) {
+ if let Some(long_name) = LongName::parse(pair, decoder).issue_warning(&decoder.warn) {
names.push(long_name);
}
}
pub struct ProductInfoRecord(pub String);
impl ProductInfoRecord {
- const NAME: &'static str = "extra product info";
fn decode(source: &TextRecord, decoder: &Decoder) -> Self {
Self(decoder.decode(&source.text).into())
}
}
impl VariableSet {
- fn parse(input: &str, decoder: &Decoder) -> Result<Self, Error> {
- let (name, input) = input.split_once('=').ok_or(Error::TBD)?;
+ fn parse(input: &str, decoder: &Decoder) -> Result<Self, Warning> {
+ let (name, input) = input.split_once('=').ok_or(Warning::TBD)?;
let mut vars = Vec::new();
for var in input.split_ascii_whitespace() {
if let Some(identifier) = decoder
.new_identifier(var)
- .map_err(Error::InvalidVariableSetName)
- .warn_on_error(&decoder.warn)
+ .map_err(Warning::InvalidVariableSetName)
+ .issue_warning(&decoder.warn)
{
vars.push(identifier);
}
let mut sets = Vec::new();
let input = decoder.decode(&source.text);
for line in input.lines() {
- if let Some(set) = VariableSet::parse(line, decoder).warn_on_error(&decoder.warn) {
+ if let Some(set) = VariableSet::parse(line, decoder).issue_warning(&decoder.warn) {
sets.push(set)
}
}
}
}
-trait WarnOnError<T> {
- fn warn_on_error<F: Fn(Error)>(self, warn: &F) -> Option<T>;
+trait IssueWarning<T> {
+ fn issue_warning<F>(self, warn: &F) -> Option<T>
+ where
+ F: Fn(Warning);
}
-impl<T> WarnOnError<T> for Result<T, Error> {
- fn warn_on_error<F: Fn(Error)>(self, warn: &F) -> Option<T> {
+impl<T> IssueWarning<T> for Result<T, Warning> {
+ fn issue_warning<F>(self, warn: &F) -> Option<T>
+ where
+ F: Fn(Warning),
+ {
match self {
Ok(result) => Some(result),
Err(error) => {
}
impl Extension {
- fn check_size<E: ExtensionRecord>(&self) -> Result<(), Error> {
+ fn check_size<E: ExtensionRecord>(&self) -> Result<(), Warning> {
if let Some(expected_size) = E::SIZE {
if self.size != expected_size {
- return Err(Error::BadRecordSize {
+ return Err(Warning::BadRecordSize {
offset: self.offsets.start,
record: E::NAME.into(),
size: self.size,
}
if let Some(expected_count) = E::COUNT {
if self.count != expected_count {
- return Err(Error::BadRecordCount {
+ return Err(Warning::BadRecordCount {
offset: self.offsets.start,
record: E::NAME.into(),
count: self.count,
r: &mut R,
endian: Endian,
n_vars: usize,
- warn: &Box<dyn Fn(Error)>,
+ warn: &Box<dyn Fn(Warning)>,
) -> Result<Option<Record>, Error> {
let subtype = endian.parse(read_bytes(r)?);
let header_offset = r.stream_position()?;
fn decode<'a>(
&'a self,
decoder: &Decoder,
- ) -> Result<LongStringValueLabels<Identifier, Cow<'a, str>>, Error> {
+ ) -> Result<LongStringValueLabels<Identifier, Cow<'a, str>>, Warning> {
let var_name = decoder.decode(&self.var_name);
let var_name = Identifier::new(var_name.trim_end(), decoder.encoding)
- .map_err(Error::InvalidLongStringValueLabelName)?;
+ .map_err(Warning::InvalidLongStringValueLabelName)?;
let mut labels = Vec::with_capacity(self.labels.len());
for (value, label) in self.labels.iter() {
const COUNT: Option<u32> = None;
const NAME: &'static str = "long string value labels record";
- fn parse(ext: &Extension, endian: Endian) -> Result<Record, Error> {
+ fn parse(ext: &Extension, endian: Endian) -> Result<Record, Warning> {
ext.check_size::<Self>()?;
let mut input = &ext.data[..];
fn decode<'a>(
&'a self,
decoder: &Decoder,
- ) -> Result<LongStringValueLabelRecord<Identifier, Cow<'a, str>>, Error> {
+ ) -> LongStringValueLabelRecord<Identifier, Cow<'a, str>> {
let mut labels = Vec::with_capacity(self.0.len());
for label in &self.0 {
match label.decode(decoder) {
Err(error) => decoder.warn(error),
}
}
- Ok(LongStringValueLabelRecord(labels))
+ LongStringValueLabelRecord(labels)
}
}