FileAttributesRecord, FloatInfoRecord, HeaderRecord, IntegerInfoRecord, LongName,
LongNamesRecord, LongStringMissingValueRecord, LongStringValueLabelRecord,
MissingValues, MissingValuesError, MultipleResponseRecord, NumberOfCasesRecord,
- ProductInfoRecord, RawStrArray, RawString, RawWidth, ValueLabel, ValueLabelRecord,
- VarDisplayRecord, VariableAttributesRecord, VariableRecord, VariableSetRecord,
- VeryLongStringsRecord, ZHeader, ZTrailer,
+ ProductInfoRecord, RawDatum, RawString, RawWidth, ValueLabel,
+ ValueLabelRecord, VarDisplayRecord, VariableAttributesRecord, VariableRecord,
+ VariableSetRecord, VeryLongStringsRecord, ZHeader, ZTrailer,
},
},
};
pub struct Headers {
pub header: HeaderRecord<String>,
pub variable: Vec<VariableRecord<String>>,
- pub value_label: Vec<ValueLabelRecord<RawStrArray<8>, String>>,
+ pub value_label: Vec<ValueLabelRecord<RawDatum, String>>,
pub document: Vec<DocumentRecord<String>>,
pub integer_info: Option<IntegerInfoRecord>,
pub float_info: Option<FloatInfoRecord>,
/// Value labels for numeric and short string variables.
///
/// These appear after the variable records.
- ValueLabel(ValueLabelRecord<RawStrArray<8>, RawString>),
+ ValueLabel(ValueLabelRecord<RawDatum, RawString>),
/// Document record.
Document(DocumentRecord<RawDocumentLine>),
Variable(VariableRecord<String>),
/// Value label, with strings decoded.
- ValueLabel(ValueLabelRecord<RawStrArray<8>, String>),
+ ValueLabel(ValueLabelRecord<RawDatum, String>),
/// Documents, with strings decoded.
Document(DocumentRecord<String>),
}
}
-/// A [Datum] for which the character encoding and variable width is not yet known.
-pub type RawDatum = Datum<RawStrArray<8>>;
+/// A [Datum] with knowledge of string width or character encoding.
+#[derive(Copy, Clone)]
+pub enum RawDatum {
+ Number(Option<f64>),
+ String([u8; 8]),
+}
+
+impl Debug for RawDatum {
+ fn fmt(&self, f: &mut Formatter) -> FmtResult {
+ match self {
+ RawDatum::Number(Some(number)) => write!(f, "{number:?}"),
+ RawDatum::Number(None) => write!(f, "SYSMIS"),
+ RawDatum::String(s) => write!(f, "{:?}", default_decode(s)),
+ }
+ }
+}
impl RawDatum {
/// Constructs a `RawDatum` from `raw` given that we now know the variable
/// type and endianness.
pub fn from_raw(raw: &UntypedDatum, var_type: VarType, endian: Endian) -> Self {
match var_type {
- VarType::String => Datum::String(RawStrArray(raw.0)),
- VarType::Numeric => Datum::Number(endian.parse(raw.0)),
+ VarType::String => RawDatum::String(raw.0),
+ VarType::Numeric => RawDatum::Number(endian.parse(raw.0)),
}
}
Self::Number(x) => Datum::Number(*x),
Self::String(s) => {
let width = width.as_string_width().unwrap();
- Datum::String(RawString::from(&s.0[..width]))
+ Datum::String(RawString::from(&s[..width]))
}
}
}
/// 8 bytes that represent a number or a string (but that's all we know).
///
-/// Used when we don't know whether it's a number or a string, or the string
-/// width, or the character encoding.
+/// Used when we don't know whether it's a number or a string, or the numerical
+/// endianness, or the string width, or the character encoding. Really all we
+/// know is that it's 8 bytes that mean something.
#[derive(Copy, Clone)]
pub struct UntypedDatum(pub [u8; 8]);
}
#[derive(Clone, Debug)]
-pub struct ValueLabel<V, S>
+pub struct ValueLabel<D, S>
where
- V: Debug,
+ D: Debug,
S: Debug,
{
- pub datum: Datum<V>,
+ pub datum: D,
pub label: S,
}
#[derive(Clone)]
-pub struct ValueLabelRecord<V, S>
+pub struct ValueLabelRecord<D, S>
where
- V: Debug,
+ D: Debug,
S: Debug,
{
/// Range of offsets in file.
pub offsets: Range<u64>,
/// The labels.
- pub labels: Vec<ValueLabel<V, S>>,
+ pub labels: Vec<ValueLabel<D, S>>,
/// The 1-based indexes of the variable indexes.
pub dict_indexes: Vec<u32>,
pub var_type: VarType,
}
-impl<V, S> Debug for ValueLabelRecord<V, S>
+impl<D, S> Debug for ValueLabelRecord<D, S>
where
- V: Debug,
+ D: Debug,
S: Debug,
{
fn fmt(&self, f: &mut Formatter) -> FmtResult {
}
}
-impl<V, S> ValueLabelRecord<V, S>
+impl<D, S> ValueLabelRecord<D, S>
where
- V: Debug,
+ D: Debug,
S: Debug,
{
/// Maximum number of value labels in a record.
pub const MAX_INDEXES: u32 = u32::MAX / 8;
}
-impl ValueLabelRecord<RawStrArray<8>, RawString> {
+impl ValueLabelRecord<RawDatum, RawString> {
fn read<R: Read + Seek>(
r: &mut R,
endian: Endian,
let labels = labels
.into_iter()
.map(|(value, label)| ValueLabel {
- datum: Datum::from_raw(&value, var_type, endian),
+ datum: RawDatum::from_raw(&value, var_type, endian),
label,
})
.collect();
})))
}
- fn decode(self, decoder: &mut Decoder) -> ValueLabelRecord<RawStrArray<8>, String> {
+ fn decode(self, decoder: &mut Decoder) -> ValueLabelRecord<RawDatum, String> {
let labels = self
.labels
.iter()