Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
Byron committed Aug 24, 2020
1 parent e03e0e5 commit fb7dd26
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 150 deletions.
4 changes: 2 additions & 2 deletions git-packetline/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ pub struct RemoteProgress<'a> {
pub mod borrowed;
pub use borrowed::Borrowed as PacketLine;

pub mod read;
pub mod reader;
#[doc(inline)]
pub use read::Reader;
pub use reader::Reader;

pub mod write;
pub use write::Writer;
Expand Down
152 changes: 4 additions & 148 deletions git-packetline/src/read.rs → git-packetline/src/reader/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use crate::{
borrowed::{Band, Text},
decode, MAX_DATA_LEN, MAX_LINE_LEN, U16_HEX_BYTES,
};
use crate::{decode, MAX_LINE_LEN, U16_HEX_BYTES};
use crate::{PacketLine, RemoteProgress};
use bstr::ByteSlice;
use git_features::{progress, progress::Progress};
use std::io;

mod read;
pub use read::ReadWithProgress;

/// Read pack lines one after another, without consuming more than needed from the underlying
/// `Read`. `Flush` lines cause the reader to stop producing lines forever, leaving `Read` at the
/// start of whatever comes next.
Expand Down Expand Up @@ -153,147 +153,3 @@ where
ReadWithProgress::new(self)
}
}

type ProgressAndParser<P> = (P, fn(&[u8]) -> Option<RemoteProgress>);

pub struct ReadWithProgress<'a, T, P>
where
T: io::Read,
{
parent: &'a mut Reader<T>,
progress_and_parse: Option<ProgressAndParser<P>>,
buf: Vec<u8>,
pos: usize,
cap: usize,
}

impl<'a, T, P> Drop for ReadWithProgress<'a, T, P>
where
T: io::Read,
{
fn drop(&mut self) {
self.parent.reset();
}
}

impl<'a, T> ReadWithProgress<'a, T, progress::Discard>
where
T: io::Read,
{
fn new(parent: &'a mut Reader<T>) -> Self {
ReadWithProgress {
parent,
progress_and_parse: None,
buf: vec![0; MAX_DATA_LEN],
pos: 0,
cap: 0,
}
}
}

impl<'a, T, P> ReadWithProgress<'a, T, P>
where
T: io::Read,
P: Progress,
{
fn with_progress(
parent: &'a mut Reader<T>,
progress: P,
parse_progress: fn(&[u8]) -> Option<RemoteProgress>,
) -> Self {
ReadWithProgress {
parent,
progress_and_parse: Some((progress, parse_progress)),
buf: vec![0; MAX_DATA_LEN],
pos: 0,
cap: 0,
}
}
}

impl<'a, T, P> io::BufRead for ReadWithProgress<'a, T, P>
where
T: io::Read,
P: Progress,
{
fn fill_buf(&mut self) -> io::Result<&[u8]> {
use io::Read;
if self.pos >= self.cap {
debug_assert!(self.pos == self.cap);
self.cap = loop {
let line = match self.parent.read_line() {
Some(line) => line?.map_err(|err| io::Error::new(io::ErrorKind::Other, err))?,
None => break 0,
};
match self.progress_and_parse.as_mut() {
Some((progress, parse_progress)) => {
let mut band = line
.decode_band()
.map_err(|err| io::Error::new(io::ErrorKind::Other, err))?;
fn progress_name(current: Option<String>, action: &[u8]) -> String {
match current {
Some(current) => format!("{}: {}", current, action.as_bstr()),
None => action.as_bstr().to_string(),
}
}
match band {
Band::Data(ref mut d) => break d.read(&mut self.buf)?,
Band::Progress(d) => {
let text = Text::from(d).0;
match (parse_progress)(text) {
Some(RemoteProgress {
action,
percent: _,
step,
max,
}) => {
progress.set_name(progress_name(progress.name(), action));
progress.init(max, git_features::progress::count("objects"));
if let Some(step) = step {
progress.set(step);
}
}
None => progress.set_name(progress_name(progress.name(), text)),
};
}
Band::Error(d) => progress.fail(progress_name(None, Text::from(d).as_slice())),
};
}
None => {
break match line.as_slice() {
Some(ref mut d) => d.read(&mut self.buf)?,
None => {
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"encountered non-data line in a data-line only context",
))
}
}
}
}
};
self.pos = 0;
}
Ok(&self.buf[self.pos..self.cap])
}

fn consume(&mut self, amt: usize) {
self.pos = std::cmp::min(self.pos + amt, self.cap);
}
}

impl<'a, T, P> io::Read for ReadWithProgress<'a, T, P>
where
T: io::Read,
P: Progress,
{
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
use std::io::BufRead;
let nread = {
let mut rem = self.fill_buf()?;
rem.read(buf)?
};
self.consume(nread);
Ok(nread)
}
}
151 changes: 151 additions & 0 deletions git-packetline/src/reader/read.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
use crate::{
borrowed::{Band, Text},
Reader, RemoteProgress, MAX_DATA_LEN,
};
use bstr::ByteSlice;
use git_features::{progress, progress::Progress};
use std::io;

type ProgressAndParser<P> = (P, fn(&[u8]) -> Option<RemoteProgress>);

pub struct ReadWithProgress<'a, T, P>
where
T: io::Read,
{
parent: &'a mut Reader<T>,
progress_and_parse: Option<ProgressAndParser<P>>,
buf: Vec<u8>,
pos: usize,
cap: usize,
}

impl<'a, T, P> Drop for ReadWithProgress<'a, T, P>
where
T: io::Read,
{
fn drop(&mut self) {
self.parent.reset();
}
}

impl<'a, T> ReadWithProgress<'a, T, progress::Discard>
where
T: io::Read,
{
pub fn new(parent: &'a mut Reader<T>) -> Self {
ReadWithProgress {
parent,
progress_and_parse: None,
buf: vec![0; MAX_DATA_LEN],
pos: 0,
cap: 0,
}
}
}

impl<'a, T, P> ReadWithProgress<'a, T, P>
where
T: io::Read,
P: Progress,
{
pub fn with_progress(
parent: &'a mut Reader<T>,
progress: P,
parse_progress: fn(&[u8]) -> Option<RemoteProgress>,
) -> Self {
ReadWithProgress {
parent,
progress_and_parse: Some((progress, parse_progress)),
buf: vec![0; MAX_DATA_LEN],
pos: 0,
cap: 0,
}
}
}

impl<'a, T, P> io::BufRead for ReadWithProgress<'a, T, P>
where
T: io::Read,
P: Progress,
{
fn fill_buf(&mut self) -> io::Result<&[u8]> {
use io::Read;
if self.pos >= self.cap {
debug_assert!(self.pos == self.cap);
self.cap = loop {
let line = match self.parent.read_line() {
Some(line) => line?.map_err(|err| io::Error::new(io::ErrorKind::Other, err))?,
None => break 0,
};
match self.progress_and_parse.as_mut() {
Some((progress, parse_progress)) => {
let mut band = line
.decode_band()
.map_err(|err| io::Error::new(io::ErrorKind::Other, err))?;
fn progress_name(current: Option<String>, action: &[u8]) -> String {
match current {
Some(current) => format!("{}: {}", current, action.as_bstr()),
None => action.as_bstr().to_string(),
}
}
match band {
Band::Data(ref mut d) => break d.read(&mut self.buf)?,
Band::Progress(d) => {
let text = Text::from(d).0;
match (parse_progress)(text) {
Some(RemoteProgress {
action,
percent: _,
step,
max,
}) => {
progress.set_name(progress_name(progress.name(), action));
progress.init(max, git_features::progress::count("objects"));
if let Some(step) = step {
progress.set(step);
}
}
None => progress.set_name(progress_name(progress.name(), text)),
};
}
Band::Error(d) => progress.fail(progress_name(None, Text::from(d).as_slice())),
};
}
None => {
break match line.as_slice() {
Some(ref mut d) => d.read(&mut self.buf)?,
None => {
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"encountered non-data line in a data-line only context",
))
}
}
}
}
};
self.pos = 0;
}
Ok(&self.buf[self.pos..self.cap])
}

fn consume(&mut self, amt: usize) {
self.pos = std::cmp::min(self.pos + amt, self.cap);
}
}

impl<'a, T, P> io::Read for ReadWithProgress<'a, T, P>
where
T: io::Read,
P: Progress,
{
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
use std::io::BufRead;
let nread = {
let mut rem = self.fill_buf()?;
rem.read(buf)?
};
self.consume(nread);
Ok(nread)
}
}

0 comments on commit fb7dd26

Please sign in to comment.