work
[pspp] / rust / src / cooked.rs
index 3c0d2e4ff60af1210c0c3a01640a18835bf06aa2..93fe21f2bd39edbb0963ea35c94445439dad530b 100644 (file)
@@ -1,12 +1,12 @@
-use std::{borrow::Cow, collections::{HashSet, HashMap}};
+use std::{borrow::Cow, collections::{HashSet, HashMap}, cmp::Ordering};
 
 use chrono::{NaiveDate, NaiveDateTime, NaiveTime};
 use encoding_rs::Encoding;
 use num::integer::div_ceil;
 use crate::{
-    format::{Spec, UncheckedSpec, Width},
+    format::{Spec, UncheckedSpec},
     identifier::{Error as IdError, Identifier},
-    raw::{self, MissingValues},
+    raw::{self, MissingValues, VarType},
     {endian::Endian, Compression},
 };
 use thiserror::Error as ThisError;
@@ -57,10 +57,10 @@ impl Decoder {
             assert!(self.n_generated_names < usize::MAX);
         }
     }
-    fn take_dict_indexes(&mut self, id: &Identifier, width: Width) -> usize {
+    fn take_dict_indexes(&mut self, id: &Identifier, width: VarWidth) -> usize {
         let n = match width {
-            0 => 1,
-            w => div_ceil(w, 8) as usize,
+            VarWidth::Numeric => 1,
+            VarWidth::String(w) => div_ceil(w as usize, 8),
         };
         let dict_index = self.n_dict_indexes;
         self.dict_indexes.insert(self.n_dict_indexes, id.clone());
@@ -122,8 +122,33 @@ impl Decode for Header {
     }
 }
 
+#[derive(Copy, Clone, PartialEq, Eq)]
+pub enum VarWidth {
+    Numeric,
+    String(u16),
+}
+
+impl PartialOrd for VarWidth {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        match (self, other) {
+            (VarWidth::Numeric, VarWidth::Numeric) => Some(Ordering::Equal),
+            (VarWidth::String(a), VarWidth::String(b)) => Some(a.cmp(b)),
+            _ => None,
+        }
+    }
+}
+
+impl From<VarWidth> for VarType {
+    fn from(source: VarWidth) -> Self {
+        match source {
+            VarWidth::Numeric => VarType::Numeric,
+            VarWidth::String(_) => VarType::String,
+        }
+    }
+}
+
 pub struct Variable {
-    pub width: Width,
+    pub width: VarWidth,
     pub name: Identifier,
     pub print_format: Spec,
     pub write_format: Spec,
@@ -131,7 +156,7 @@ pub struct Variable {
     pub label: Option<String>,
 }
 
-fn decode_format(raw: raw::Spec, name: &str, width: Width) -> Spec {
+fn decode_format(raw: raw::Spec, name: &str, width: VarWidth) -> Spec {
     UncheckedSpec::try_from(raw)
         .and_then(Spec::try_from)
         .and_then(|x| x.check_width_compatibility(Some(name), width))
@@ -147,8 +172,9 @@ impl Variable {
         input: &crate::raw::Variable,
         warn: impl Fn(Error),
     ) -> Result<Option<Variable>, Error> {
-        match input.width {
-            0..=255 => (),
+        let width = match input.width {
+            0 => VarWidth::Numeric,
+            w @ 1..=255 => VarWidth::String(w as u16),
             -1 => return Ok(None),
             _ => {
                 return Err(Error::BadVariableWidth {
@@ -157,7 +183,6 @@ impl Variable {
                 })
             }
         };
-        let width = input.width as Width;
         let name = decoder.decode_string(&input.name.0, &warn);
         let name = match Identifier::new(&name, decoder.encoding) {
             Ok(name) => {
@@ -234,6 +259,11 @@ impl VariableSet {
     }
 }
 
+/*
+pub struct ValueLabelRecord {
+    pub labels: Vec<(
+}
+*/
 pub struct VariableSetRecord(Vec<VariableSet>);
 
 impl TextRecord for VariableSetRecord {