Skip to content

Commit

Permalink
refactor PackIndexReader
Browse files Browse the repository at this point in the history
create explicit struct reading pack indexes
use generics rather than trait objects as casting from &Trait to &SuperTrait is not implemented (rust-lang/rfcs#2765)
and its very inconveninent to not be able to pass `&mut BufReadSeek` to a function that expects a `&mut BufRead`.
Furthermore, the main reason we were using dynamic dispatch in the first
place was just to make certain traits (Serialize & hence BitObj) object safe. I think Deserialize was rewritten to use dyn to be consistent with Serialize.
  • Loading branch information
andyyu2004 committed May 5, 2021
1 parent c8a8e08 commit 9594d94
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 12 deletions.
69 changes: 61 additions & 8 deletions src/libbit/src/pack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::hash::{BitHash, SHA1Hash, BIT_HASH_SIZE};
use crate::io::{BufReadExt, HashReader, ReadExt};
use crate::serialize::{BufReadSeek, Deserialize};
use std::io::{BufRead, SeekFrom};
use std::ops::{Deref, DerefMut};

const PACK_IDX_MAGIC: u32 = 0xff744f63;
const FANOUT_ENTRYC: usize = 256;
Expand All @@ -18,10 +19,48 @@ pub struct PackIndex {
pack_hash: SHA1Hash,
}

impl PackIndex {
fn find_oid_index(mut r: &mut dyn BufReadSeek, oid: BitHash) -> BitResult<usize> {
r.seek(SeekFrom::Start(PACK_IDX_HEADER_SIZE))?;
let fanout = r.read_array::<u32, FANOUT_ENTRYC>()?;
pub struct PackIndexReader<'r, R> {
reader: &'r mut R,
fanout: [u32; FANOUT_ENTRYC],
}

#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
enum Layer {
Fan,
Oid,
Crc,
Ofs,
Ext,
}

impl<'r, R: BufReadSeek> PackIndexReader<'r, R> {
pub fn new(reader: &'r mut R) -> BitResult<Self> {
let header = PackIndex::parse_header(reader);
let fanout = reader.read_array::<u32, FANOUT_ENTRYC>()?;
Ok(Self { reader, fanout })
}
}

impl<'r, R: BufReadSeek> PackIndexReader<'r, R> {
fn offset_of(&mut self, layer: Layer) -> u64 {
match layer {
Layer::Fan => PACK_IDX_HEADER_SIZE,
Layer::Oid => PACK_IDX_HEADER_SIZE,
Layer::Crc => todo!(),
Layer::Ofs => todo!(),
Layer::Ext => todo!(),
}
}

fn find_oid_offset(&mut self, oid: BitHash) -> BitResult<usize> {
todo!()
}

fn read_from<T: Deserialize>(&mut self, layer: Layer) -> BitResult<T> {
todo!()
}

fn find_oid_index(&mut self, oid: BitHash) -> BitResult<usize> {
// fanout has 256 elements
// example
// [
Expand All @@ -45,18 +84,32 @@ impl PackIndex {
//
let prefix = oid[0] as usize;
// low..high (inclusive lower bound, exclusive upper bound)
let low = if prefix == 0 { 0 } else { fanout[prefix - 1] } as i64;
let high = fanout[prefix] as i64;
let low = if prefix == 0 { 0 } else { self.fanout[prefix - 1] } as i64;
let high = self.fanout[prefix] as i64;

r.seek(SeekFrom::Current(low * BIT_HASH_SIZE as i64))?;
let oids = r.read_vec((high - low) as usize)?;
self.seek(SeekFrom::Current(low * BIT_HASH_SIZE as i64))?;
let oids = self.reader.read_vec((high - low) as usize)?;
match oids.binary_search(&oid) {
Ok(idx) => Ok(low as usize + idx),
Err(..) => Err(anyhow!("oid `{}` not found in packindex", oid)),
}
}
}

impl<'r, R> Deref for PackIndexReader<'r, R> {
type Target = R;

fn deref(&self) -> &Self::Target {
&self.reader
}
}

impl<'r, R> DerefMut for PackIndexReader<'r, R> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.reader
}
}

impl Deserialize for PackIndex {
fn deserialize(reader: &mut dyn BufRead) -> BitResult<Self>
where
Expand Down
6 changes: 2 additions & 4 deletions src/libbit/src/pack/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ fn test_deserialize_pack_idx_is_ok() -> BitResult<()> {
#[test]
fn test_pack_idx_find_oid_start() -> BitResult<()> {
let mut cursor = Cursor::new(include_bytes!("../../tests/files/pack.idx"));
let pack_idx = PackIndex::find_oid_index(
&mut cursor,
let pack_idx = PackIndexReader::new(&mut cursor)?.find_oid_index(
// this hash is the first oid in sorted list
BitHash::from_str("0004a3cf85dbcbfbef916599145a0c370bb78cf5").unwrap(),
)?;
Expand All @@ -26,8 +25,7 @@ fn test_pack_idx_find_oid_start() -> BitResult<()> {
#[test]
fn test_pack_idx_find_oid_end() -> BitResult<()> {
let mut cursor = Cursor::new(include_bytes!("../../tests/files/pack.idx"));
let pack_idx = PackIndex::find_oid_index(
&mut cursor,
let pack_idx = PackIndexReader::new(&mut cursor)?.find_oid_index(
// this hash is the last oid in sorted list
BitHash::from_str("fffc6e8cf5f6798732a6031ebf24d2f6aaa60e47").unwrap(),
)?;
Expand Down

0 comments on commit 9594d94

Please sign in to comment.