Clean up RawDatum a bit.
authorBen Pfaff <blp@cs.stanford.edu>
Sat, 12 Jul 2025 22:48:53 +0000 (15:48 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Sat, 12 Jul 2025 22:48:53 +0000 (15:48 -0700)
rust/pspp/src/sys/cooked.rs
rust/pspp/src/sys/raw.rs

index 0a6dee73cde4845601a1ef5f244ee68ae78cbb46..1db24b683c5d751c6d83479610de5c46466bf449 100644 (file)
@@ -34,9 +34,9 @@ use crate::{
             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,
         },
     },
 };
@@ -309,7 +309,7 @@ pub enum Error {
 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>,
index 926a52263e87651802acbd3b3fb2c654e992091f..969fee56f5ea07ae813eb967f77116d43d77cce6 100644 (file)
@@ -399,7 +399,7 @@ pub enum Record {
     /// 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>),
@@ -484,7 +484,7 @@ pub enum DecodedRecord {
     Variable(VariableRecord<String>),
 
     /// Value label, with strings decoded.
-    ValueLabel(ValueLabelRecord<RawStrArray<8>, String>),
+    ValueLabel(ValueLabelRecord<RawDatum, String>),
 
     /// Documents, with strings decoded.
     Document(DocumentRecord<String>),
@@ -988,16 +988,30 @@ impl TryFrom<RawWidth> for VarWidth {
     }
 }
 
-/// 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)),
         }
     }
 
@@ -1008,7 +1022,7 @@ impl RawDatum {
             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]))
             }
         }
     }
@@ -1996,8 +2010,9 @@ impl VariableRecord<RawString> {
 
 /// 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]);
 
@@ -2276,26 +2291,26 @@ impl Display for QuotedEncodedStr<'_> {
 }
 
 #[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>,
@@ -2304,9 +2319,9 @@ where
     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 {
@@ -2322,9 +2337,9 @@ where
     }
 }
 
-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.
@@ -2334,7 +2349,7 @@ where
     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,
@@ -2430,7 +2445,7 @@ impl ValueLabelRecord<RawStrArray<8>, RawString> {
         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();
@@ -2444,7 +2459,7 @@ impl ValueLabelRecord<RawStrArray<8>, RawString> {
         })))
     }
 
-    fn decode(self, decoder: &mut Decoder) -> ValueLabelRecord<RawStrArray<8>, String> {
+    fn decode(self, decoder: &mut Decoder) -> ValueLabelRecord<RawDatum, String> {
         let labels = self
             .labels
             .iter()