work
authorBen Pfaff <blp@cs.stanford.edu>
Wed, 26 Jul 2023 06:07:57 +0000 (23:07 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Wed, 26 Jul 2023 06:07:57 +0000 (23:07 -0700)
rust/src/lib.rs

index 8e8ee6cab4fad89ec9e749960b40f8330cf0cdde..0b8c541e54612fcee67b45596a6370ec128f5c5b 100644 (file)
@@ -2,7 +2,7 @@
 use endian::{Endian, Parse};
 use num::Integer;
 use num_derive::FromPrimitive;
-use std::io::{BufReader, Error as IoError, Read, Seek};
+use std::io::{BufReader, Error as IoError, ErrorKind, Read, Seek};
 use thiserror::Error;
 
 pub mod endian;
@@ -15,11 +15,11 @@ pub enum Error {
     #[error("Invalid magic number {0:?}")]
     BadMagic([u8; 4]),
 
-    #[error("I/O error ({source})")]
-    Io {
+    #[error("I/O error ({0})")]
+    Io(
         #[from]
-        source: IoError,
-    },
+        IoError,
+    ),
 
     #[error("Invalid SAV compression code {0}")]
     InvalidSavCompression(u32),
@@ -100,6 +100,7 @@ pub enum Record {
     VarIndexes(VarIndexes),
     Extension(Extension),
     EndOfHeaders,
+    Case(Vec<Value>),
 }
 
 pub struct Header {
@@ -170,7 +171,8 @@ impl TryFrom<[u8; 4]> for Magic {
     }
 }
 
-enum VarType {
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+pub enum VarType {
     Number,
     String,
 }
@@ -197,6 +199,24 @@ enum ReaderState {
     End,
 }
 
+#[derive(Copy, Clone)]
+pub enum Value {
+    Number(Option<f64>),
+    String([u8; 8]),
+}
+
+impl Value {
+    pub fn from_raw(var_type: VarType, raw: [u8; 8], endian: Endian) -> Value {
+        match var_type {
+            VarType::String => Value::String(raw),
+            VarType::Number => {
+                let number: f64 = endian.parse(raw);
+                Value::Number((number != -f64::MAX).then_some(number))
+            }
+        }
+    }
+}
+
 impl<R: Read + Seek> Reader<R> {
     pub fn new(r: R) -> Result<Reader<R>, Error> {
         Ok(Reader {
@@ -241,6 +261,23 @@ impl<R: Read + Seek> Reader<R> {
                 };
                 Ok(Some((record, ReaderState::Headers(endian, compression))))
             }
+            ReaderState::Data(endian) => {
+                let mut values = Vec::with_capacity(self.var_types.len());
+                for (i, &var_type) in self.var_types.iter().enumerate() {
+                    let raw = match read_bytes(&mut self.r) {
+                        Ok(raw) => raw,
+                        Err(err) => {
+                            if i == 0 && err.kind() == ErrorKind::UnexpectedEof {
+                                return Ok(None);
+                            } else {
+                                return Err(Error::Io(err));
+                            }
+                        }
+                    };
+                    values.push(Value::from_raw(var_type, raw, endian));
+                }
+                Ok(Some((Record::Case(values), ReaderState::Data(endian))))
+            }
             ReaderState::End => Ok(None),
         }
     }