refactor revlog-handling code into a revlogs module
2 files changed, 205 insertions(+), 202 deletions(-)

M src/main.rs
A => src/revlogs/mod.rs
M src/main.rs +2 -202
@@ 1,207 1,7 @@ 
-use byteorder::{BigEndian, ReadBytesExt};
-use flate2::read::ZlibDecoder;
 use std::env;
-use std::fmt;
 use std::fs::File;
-use std::io;
-use std::io::prelude::*;
-use std::io::Cursor;
-use std::io::SeekFrom;
-
-#[derive(Debug)]
-struct RevlogHeader {
-    offset: u64, // really 6 bytes but easier to represent as a u64
-    bitflags: [u8; 2],
-    compressedlength: u32,
-    uncompressedlength: u32,
-    baserev: i32,
-    linkrev: i32,
-    p1rev: i32,
-    p2rev: i32,
-    hash: [u8; 32],
-}
-
-impl RevlogHeader {
-    fn new(buffer: &[u8; 64]) -> Result<RevlogHeader, io::Error> {
-        let mut cursor = Cursor::new(buffer as &[u8]);
-        Ok(RevlogHeader {
-            offset: cursor.read_u48::<BigEndian>()? as u64,
-            bitflags: cursor.read_u16::<BigEndian>()?.to_be_bytes(),
-            compressedlength: cursor.read_u32::<BigEndian>()?,
-            uncompressedlength: cursor.read_u32::<BigEndian>()?,
-            baserev: cursor.read_i32::<BigEndian>()?,
-            linkrev: cursor.read_i32::<BigEndian>()?,
-            p1rev: cursor.read_i32::<BigEndian>()?,
-            p2rev: cursor.read_i32::<BigEndian>()?,
-            hash: {
-                let mut res = [0u8; 32];
-                cursor.read_exact(&mut res)?;
-                res
-            },
-        })
-    }
-}
-
-#[derive(Debug)]
-struct RevlogEntry {
-    header: RevlogHeader,
-    content: RevlogContent,
-}
-
-#[derive(Debug)]
-enum RevlogContent {
-    Generic(Vec<u8>),
-}
-
-impl RevlogEntry {
-    fn new(f: &mut File, header_buffer: &[u8; 64]) -> Result<RevlogEntry, io::Error> {
-        let header = RevlogHeader::new(&header_buffer)?;
-        let mut content_buffer = vec![0u8; header.compressedlength as usize];
-        f.read_exact(&mut content_buffer)?;
-        let decompressed_data = match content_buffer[0] {
-            0 => vec![0u8; 0],
-            0x75 => content_buffer[1..].to_vec(),
-            0x78 => {
-                let mut gz = ZlibDecoder::new(&content_buffer[..]);
-                let mut decompressed_data = String::new();
-                gz.read_to_string(&mut decompressed_data)?;
-                decompressed_data.into_bytes()
-            }
-            _ => panic!(),
-        };
-        Ok(RevlogEntry {
-            header: header,
-            content: RevlogContent::Generic(decompressed_data),
-        })
-    }
-}
 
-impl fmt::Display for RevlogHeader {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        let hash: Vec<String> = self.hash.iter().map(|b| format!("{:02x}", b)).collect();
-        write!(
-            f,
-            "offset: {}\n\
-             bitflags: {:?}\n\
-             compressed length: {}\n\
-             uncompressed length: {}\n\
-             base revision: {}\n\
-             linked revision: {}\n\
-             p1: {}\n\
-             p2: {}\n\
-             hash: {}\n",
-            self.offset,
-            self.bitflags,
-            self.compressedlength,
-            self.uncompressedlength,
-            self.baserev,
-            self.linkrev,
-            self.p1rev,
-            self.p2rev,
-            hash.join("")
-        )
-    }
-}
-
-impl fmt::Display for RevlogEntry {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "header:\n{}\ncontent: {}\n", self.header, self.content)
-    }
-}
-
-impl fmt::Display for RevlogContent {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        let printable = match self {
-            RevlogContent::Generic(s) => match std::str::from_utf8(s) {
-                Ok(parsed) => parsed.to_string(),
-                Err(_) => s
-                    .iter()
-                    .map(|c| {
-                        std::ascii::escape_default(*c)
-                            .map(|b| b as char)
-                            .collect::<String>()
-                    })
-                    .collect::<String>(),
-            },
-        };
-        write!(f, "{}", printable)
-    }
-}
-
-#[derive(Debug)]
-struct Revlog {
-    inline: bool,
-    generaldelta: bool,
-    entries: Vec<RevlogEntry>,
-}
-
-impl Revlog {
-    fn new(mut f: &mut File) -> Result<Revlog, io::Error> {
-        let mut revlog_header = [0u8; 4];
-        f.read_exact(&mut revlog_header)?;
-        let inline;
-        let generaldelta;
-        match revlog_header {
-            [0, 3, 0, 1] => {
-                inline = true;
-                generaldelta = true;
-            }
-            [0, 2, 0, 1] => {
-                inline = false;
-                generaldelta = true;
-            }
-            [0, 1, 0, 1] => {
-                inline = true;
-                generaldelta = false;
-            }
-            [0, 0, 0, 1] => {
-                inline = false;
-                generaldelta = false;
-            }
-            _ => panic!(),
-        }
-        if !inline {
-            // haven't implemented this yet
-            panic!()
-        }
-        let mut header_buffer = [0u8; 64];
-        (*f).seek(SeekFrom::Start(0))?;
-        f.read_exact(&mut header_buffer)?;
-        // zero out header in first offset entry
-        for i in 0..4 {
-            header_buffer[i] = 0;
-        }
-        let mut entries: Vec<RevlogEntry> = Vec::new();
-        loop {
-            entries.push(RevlogEntry::new(&mut f, &header_buffer)?);
-            header_buffer = [0u8; 64];
-            match f.read_exact(&mut header_buffer) {
-                Ok(_) => {}
-                Err(ref e) if e.kind() == io::ErrorKind::UnexpectedEof => break,
-                Err(e) => return Err(e),
-            };
-        }
-        Ok(Revlog {
-            inline: inline,
-            generaldelta: generaldelta,
-            entries: entries,
-        })
-    }
-}
-
-impl fmt::Display for Revlog {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(
-            f,
-            "inline:\n{}\ngeneraldelta: {}\n",
-            self.inline, self.generaldelta
-        )?;
-        for entry in &self.entries {
-            write!(f, "{}\n\n", entry)?;
-        }
-        write!(f, "")
-    }
-}
+mod revlogs;
 
 fn main() -> std::io::Result<()> {
     let args: Vec<String> = env::args().collect();

          
@@ 210,7 10,7 @@ fn main() -> std::io::Result<()> {
     // open file
     let mut f = File::open(fname)?;
 
-    let revlog = Revlog::new(&mut f)?;
+    let revlog = revlogs::Revlog::new(&mut f)?;
 
     println!("{}", revlog);
 

          
A => src/revlogs/mod.rs +203 -0
@@ 0,0 1,203 @@ 
+use byteorder::{BigEndian, ReadBytesExt};
+use flate2::read::ZlibDecoder;
+use std::fmt;
+use std::fs::File;
+use std::io;
+use std::io::prelude::*;
+use std::io::Cursor;
+use std::io::SeekFrom;
+
+#[derive(Debug)]
+struct RevlogHeader {
+    offset: u64, // really 6 bytes but easier to represent as a u64
+    bitflags: [u8; 2],
+    compressedlength: u32,
+    uncompressedlength: u32,
+    baserev: i32,
+    linkrev: i32,
+    p1rev: i32,
+    p2rev: i32,
+    hash: [u8; 32],
+}
+
+impl RevlogHeader {
+    fn new(buffer: &[u8; 64]) -> Result<RevlogHeader, io::Error> {
+        let mut cursor = Cursor::new(buffer as &[u8]);
+        Ok(RevlogHeader {
+            offset: cursor.read_u48::<BigEndian>()? as u64,
+            bitflags: cursor.read_u16::<BigEndian>()?.to_be_bytes(),
+            compressedlength: cursor.read_u32::<BigEndian>()?,
+            uncompressedlength: cursor.read_u32::<BigEndian>()?,
+            baserev: cursor.read_i32::<BigEndian>()?,
+            linkrev: cursor.read_i32::<BigEndian>()?,
+            p1rev: cursor.read_i32::<BigEndian>()?,
+            p2rev: cursor.read_i32::<BigEndian>()?,
+            hash: {
+                let mut res = [0u8; 32];
+                cursor.read_exact(&mut res)?;
+                res
+            },
+        })
+    }
+}
+
+#[derive(Debug)]
+struct RevlogEntry {
+    header: RevlogHeader,
+    content: RevlogContent,
+}
+
+#[derive(Debug)]
+enum RevlogContent {
+    Generic(Vec<u8>),
+}
+
+impl RevlogEntry {
+    fn new(f: &mut File, header_buffer: &[u8; 64]) -> Result<RevlogEntry, io::Error> {
+        let header = RevlogHeader::new(&header_buffer)?;
+        let mut content_buffer = vec![0u8; header.compressedlength as usize];
+        f.read_exact(&mut content_buffer)?;
+        let decompressed_data = match content_buffer[0] {
+            0 => vec![0u8; 0],
+            0x75 => content_buffer[1..].to_vec(),
+            0x78 => {
+                let mut gz = ZlibDecoder::new(&content_buffer[..]);
+                let mut decompressed_data = String::new();
+                gz.read_to_string(&mut decompressed_data)?;
+                decompressed_data.into_bytes()
+            }
+            _ => panic!(),
+        };
+        Ok(RevlogEntry {
+            header: header,
+            content: RevlogContent::Generic(decompressed_data),
+        })
+    }
+}
+
+impl fmt::Display for RevlogHeader {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let hash: Vec<String> = self.hash.iter().map(|b| format!("{:02x}", b)).collect();
+        write!(
+            f,
+            "offset: {}\n\
+             bitflags: {:?}\n\
+             compressed length: {}\n\
+             uncompressed length: {}\n\
+             base revision: {}\n\
+             linked revision: {}\n\
+             p1: {}\n\
+             p2: {}\n\
+             hash: {}\n",
+            self.offset,
+            self.bitflags,
+            self.compressedlength,
+            self.uncompressedlength,
+            self.baserev,
+            self.linkrev,
+            self.p1rev,
+            self.p2rev,
+            hash.join("")
+        )
+    }
+}
+
+impl fmt::Display for RevlogEntry {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "header:\n{}\ncontent: {}\n", self.header, self.content)
+    }
+}
+
+impl fmt::Display for RevlogContent {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let printable = match self {
+            RevlogContent::Generic(s) => match std::str::from_utf8(s) {
+                Ok(parsed) => parsed.to_string(),
+                Err(_) => s
+                    .iter()
+                    .map(|c| {
+                        std::ascii::escape_default(*c)
+                            .map(|b| b as char)
+                            .collect::<String>()
+                    })
+                    .collect::<String>(),
+            },
+        };
+        write!(f, "{}", printable)
+    }
+}
+
+#[derive(Debug)]
+pub struct Revlog {
+    inline: bool,
+    generaldelta: bool,
+    entries: Vec<RevlogEntry>,
+}
+
+impl Revlog {
+    pub fn new(mut f: &mut File) -> Result<Revlog, io::Error> {
+        let mut revlog_header = [0u8; 4];
+        f.read_exact(&mut revlog_header)?;
+        let inline;
+        let generaldelta;
+        match revlog_header {
+            [0, 3, 0, 1] => {
+                inline = true;
+                generaldelta = true;
+            }
+            [0, 2, 0, 1] => {
+                inline = false;
+                generaldelta = true;
+            }
+            [0, 1, 0, 1] => {
+                inline = true;
+                generaldelta = false;
+            }
+            [0, 0, 0, 1] => {
+                inline = false;
+                generaldelta = false;
+            }
+            _ => panic!(),
+        }
+        if !inline {
+            // haven't implemented this yet
+            panic!()
+        }
+        let mut header_buffer = [0u8; 64];
+        (*f).seek(SeekFrom::Start(0))?;
+        f.read_exact(&mut header_buffer)?;
+        // zero out header in first offset entry
+        for i in 0..4 {
+            header_buffer[i] = 0;
+        }
+        let mut entries: Vec<RevlogEntry> = Vec::new();
+        loop {
+            entries.push(RevlogEntry::new(&mut f, &header_buffer)?);
+            header_buffer = [0u8; 64];
+            match f.read_exact(&mut header_buffer) {
+                Ok(_) => {}
+                Err(ref e) if e.kind() == io::ErrorKind::UnexpectedEof => break,
+                Err(e) => return Err(e),
+            };
+        }
+        Ok(Revlog {
+            inline: inline,
+            generaldelta: generaldelta,
+            entries: entries,
+        })
+    }
+}
+
+impl fmt::Display for Revlog {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(
+            f,
+            "inline:\n{}\ngeneraldelta: {}\n",
+            self.inline, self.generaldelta
+        )?;
+        for entry in &self.entries {
+            write!(f, "{}\n\n", entry)?;
+        }
+        write!(f, "")
+    }
+}