work
[pspp] / rust / src / raw.rs
index b09f94e73aab65fc254d6bab98253dd178c0c0e9..3f7309c7ce67cb0584a83c2efb1f415ec1100674 100644 (file)
@@ -759,6 +759,71 @@ enum ExtensionType {
 }
  */
 
+trait ExtensionRecord where Self: Sized {
+    const SIZE: Option<u32>;
+    const COUNT: Option<u32>;
+    const NAME: &'static str;
+    fn parse(ext: &Extension, endian: Endian) -> Result<Self, Error>;
+}
+
+pub struct IntegerInfo {
+    version: (i32, i32, i32),
+    machine_code: i32,
+    floating_point_rep: i32,
+    compression_code: i32,
+    endianness: i32,
+    character_code: i32,
+}
+
+impl ExtensionRecord for IntegerInfo {
+    const SIZE: Option<u32> = Some(4);
+    const COUNT: Option<u32> = Some(8);
+    const NAME: &'static str = "integer record";
+
+    fn parse(ext: &Extension, endian: Endian) -> Result<Self, Error>{
+        ext.check_size::<Self>()?;
+
+        let mut input = &ext.data[..];
+        let data: Vec<i32> = (0..8)
+            .map(|_| endian.parse(read_bytes(&mut input).unwrap()))
+            .collect();
+        Ok(IntegerInfo {
+            version: (data[0], data[1], data[2]),
+            machine_code: data[3],
+            floating_point_rep: data[4],
+            compression_code: data[5],
+            endianness: data[6],
+            character_code: data[7]
+        })
+    }
+}
+
+pub struct FloatInfo {
+    sysmis: f64,
+    highest: f64,
+    lowest: f64,
+}
+
+impl ExtensionRecord for FloatInfo {
+    const SIZE: Option<u32> = Some(8);
+    const COUNT: Option<u32> = Some(3);
+    const NAME: &'static str = "floating point record";
+
+    fn parse(ext: &Extension, endian: Endian) -> Result<Self, Error>{
+        ext.check_size::<Self>()?;
+
+        let mut input = &ext.data[..];
+        let data: Vec<f64> = (0..3)
+            .map(|_| endian.parse(read_bytes(&mut input).unwrap()))
+            .collect();
+        Ok(FloatInfo {
+            sysmis: data[0],
+            highest: data[1],
+            lowest: data[2],
+        })
+    }
+}
+
 pub struct Extension {
     /// Offset from the start of the file to the start of the record.
     pub offset: u64,
@@ -805,6 +870,30 @@ fn extension_record_size_requirements(extension: ExtensionType) -> (u32, u32) {
  */
 
 impl Extension {
+    fn check_size<E: ExtensionRecord>(&self) -> Result<(), Error> {
+        if let Some(expected_size) = E::SIZE {
+            if self.size != expected_size {
+                return Err(Error::BadRecordSize {
+                    offset: self.offset,
+                    record: E::NAME.into(),
+                    size: self.size,
+                    expected_size,
+                });
+            }
+        }
+        if let Some(expected_count) = E::COUNT {
+            if self.count != expected_count {
+                return Err(Error::BadRecordCount {
+                    offset: self.offset,
+                    record: E::NAME.into(),
+                    count: self.count,
+                    expected_count,
+                });
+            }
+        }
+        Ok(())
+    }
+
     fn read<R: Read + Seek>(r: &mut R, endian: Endian) -> Result<Extension, Error> {
         let subtype = endian.parse(read_bytes(r)?);
         let offset = r.stream_position()?;
@@ -895,10 +984,7 @@ pub struct ZBlock {
 }
 
 impl ZBlock {
-    fn read<R: Read + Seek>(
-        r: &mut R,
-        endian: Endian,
-    ) -> Result<ZBlock, Error> {
+    fn read<R: Read + Seek>(r: &mut R, endian: Endian) -> Result<ZBlock, Error> {
         Ok(ZBlock {
             uncompressed_ofs: endian.parse(read_bytes(r)?),
             compressed_ofs: endian.parse(read_bytes(r)?),
@@ -933,8 +1019,8 @@ impl ZTrailer {
             });
         }
         let blocks = (0..n_blocks)
-                    .map(|_| ZBlock::read(reader, endian))
-                    .collect::<Result<Vec<_>, _>>()?;
+            .map(|_| ZBlock::read(reader, endian))
+            .collect::<Result<Vec<_>, _>>()?;
         reader.seek(SeekFrom::Start(start_offset))?;
         Ok(Some(ZTrailer {
             offset: ztrailer_ofs,