Split git_object module
git_object is going to be a big module. So let's create a folder for it. Create a folder, git_object
and move git_object.rs
to git_object/mod.rs
Add this pub use to src/lib.rs
:
pub use git_object::GitObject;
Create a new module in git_object
folder, header.rs
. Let's move Type
from mod.rs to this newly created file:
v[derive(PartialEq, PartialOrd, Debug, Clone, Copy)]
pub enum Type {
Commit,
Tree,
Tag,
Blob,
}
impl FromStr for Type {
type Err = ObjectParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"commit" => Ok(Type::Commit),
"tree" => Ok(Type::Tree),
"tag" => Ok(Type::Tag),
"blob" => Ok(Type::Blob),
_ => Err(ObjectParseError::InvalidObjectType),
}
}
}
impl Display for Type {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let string = match self {
Type::Commit => "commit",
Type::Tree => "tree",
Type::Tag => "tag",
Type::Blob => "blob",
};
write!(f, "{}", string)
}
}
Now, let's create the Header struct itself:
#[derive(Debug, PartialEq, PartialOrd)]
pub struct Header {
pub object_type: Type,
pub object_size: usize,
}
impl Header {
pub fn new(object_type: Type, object_size: usize) -> Self {
Self {
object_type,
object_size,
}
}
pub fn load(buf_reader: &mut impl std::io::BufRead) -> Result<Self, ObjectParseError> {
let mut buffer = Vec::new();
let length = buf_reader
.read_until(b' ', &mut buffer)
.context("Failed to read object type")?;
let object_type = String::from_utf8_lossy(&buffer[..length - 1]);
let object_type: Type = object_type.parse()?;
buffer = Vec::new();
let length = buf_reader.read_until(b'\x00', &mut buffer)?;
let object_size = String::from_utf8_lossy(&buffer[..length - 1]);
let object_size = object_size.parse()?;
Ok(Header {
object_type,
object_size,
})
}
}
impl Display for Header {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} {}\x00", self.object_type, self.object_size,)
}
}
We moved parse_object_file_header
from mod.rs to impl
block of this struct. We also implemented the Display
trait for this struct. It just writes the header as expected in a git object file header.
Add these two tests in header.rs
#[cfg(test)]
mod tests {
use super::Type;
use super::Header;
#[test]
fn parse_object_file_header_should_read_correct_header() -> Result<(), anyhow::Error> {
// 00000000 63 6f 6d 6d 69 74 20 31 30 38 36 00 74 72 65 65 |commit 1086.tree|
let object_header = hex::decode("636f6d6d697420313038360074726565").unwrap();
let object_header = Header::load(&mut object_header.as_ref())?;
assert_eq!(object_header.object_type, Type::Commit);
assert_eq!(object_header.object_size, 1086);
Ok(())
}
#[test]
fn to_string_of_header_should_serialize_it_correctly() -> Result<(), anyhow::Error> {
let header = Header::new(Type::Tag, 1000);
let serialized = format!("{}", header);
let loaded = Header::load(&mut serialized.as_bytes()).unwrap();
assert_eq!(header, loaded);
Ok(())
}
}
Last updated