Skip to content

Commit

Permalink
[clone] FAIL: can't pass line reader as box
Browse files Browse the repository at this point in the history
  • Loading branch information
Byron committed Aug 20, 2020
1 parent 4ba123b commit 633341d
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 123 deletions.
6 changes: 6 additions & 0 deletions git-packetline/src/borrowed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,12 @@ impl<'a> From<&'a [u8]> for Text<'a> {
}

impl<'a> Text<'a> {
pub fn as_slice(&self) -> &[u8] {
self.0
}
pub fn as_bstr(&self) -> &BStr {
self.0.into()
}
pub fn to_write(&self, out: impl io::Write) -> Result<usize, encode::Error> {
encode::text_to_write(self.0, out)
}
Expand Down
117 changes: 1 addition & 116 deletions git-packetline/src/read.rs
Original file line number Diff line number Diff line change
@@ -1,118 +1,3 @@
pub mod borrowed {
use crate::{
borrowed::{Band, Text},
decode, MAX_DATA_LEN, MAX_LINE_LEN, U16_HEX_BYTES,
};
use crate::{PacketLine, RemoteProgress};
use bstr::ByteSlice;
use git_features::{progress, progress::Progress};
use std::io;

/// 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.
pub struct Reader<'a, T> {
pub inner: T,
peek_buf: Vec<u8>,
buf: &'a mut Vec<u8>,
delimiter: PacketLine<'static>,
is_done: bool,
}

impl<'a, T> Reader<'a, T>
where
T: io::Read,
{
pub fn new(inner: T, buf: &'a mut Vec<u8>, delimiter: impl Into<Option<PacketLine<'static>>>) -> Self {
Reader {
inner,
buf,
peek_buf: Vec::new(),
delimiter: delimiter.into().unwrap_or(PacketLine::Flush),
is_done: false,
}
}

pub fn reset(&mut self) {
debug_assert!(self.is_done, "reset is only effective if we are actually done");
self.is_done = false;
}

pub fn reset_with(&mut self, delimiter: PacketLine<'static>) {
self.delimiter = delimiter;
self.is_done = false;
}

fn read_line_inner<'b>(
reader: &mut T,
buf: &'b mut Vec<u8>,
) -> io::Result<Result<PacketLine<'b>, decode::Error>> {
let (hex_bytes, data_bytes) = buf.split_at_mut(4);
reader.read_exact(hex_bytes)?;
let num_data_bytes = match decode::hex_prefix(hex_bytes) {
Ok(decode::PacketLineOrWantedSize::Line(line)) => return Ok(Ok(line)),
Ok(decode::PacketLineOrWantedSize::Wanted(additional_bytes)) => additional_bytes as usize,
Err(err) => return Ok(Err(err)),
};

let (data_bytes, _) = data_bytes.split_at_mut(num_data_bytes);
reader.read_exact(data_bytes)?;
match decode::to_data_line(data_bytes) {
Ok(line) => Ok(Ok(line)),
Err(err) => Ok(Err(err)),
}
}

pub fn read_line(&mut self) -> Option<io::Result<Result<PacketLine, decode::Error>>> {
if self.is_done {
return None;
}
if !self.peek_buf.is_empty() {
std::mem::swap(&mut self.peek_buf, self.buf);
self.peek_buf.clear();
return Some(Ok(Ok(crate::decode(&self.buf).expect("only valid data in peek buf"))));
} else if self.buf.len() != MAX_LINE_LEN {
self.buf.resize(MAX_LINE_LEN, 0);
}
match Self::read_line_inner(&mut self.inner, &mut self.buf) {
Ok(Ok(line)) if line == self.delimiter => {
self.is_done = true;
None
}
res => Some(res),
}
}

pub fn peek_line(&mut self) -> Option<io::Result<Result<PacketLine, decode::Error>>> {
if self.is_done {
return None;
}
Some(if self.peek_buf.is_empty() {
self.peek_buf.resize(MAX_LINE_LEN, 0);
match Self::read_line_inner(&mut self.inner, &mut self.peek_buf) {
Ok(Ok(line)) => {
let len = line
.as_slice()
.map(|s| s.len() + U16_HEX_BYTES)
.unwrap_or(U16_HEX_BYTES);
self.peek_buf.resize(len, 0);
Ok(Ok(crate::decode(&self.peek_buf).expect("only valid data here")))
}
Ok(Err(err)) => {
self.peek_buf.clear();
Ok(Err(err))
}
Err(err) => {
self.peek_buf.clear();
Err(err)
}
}
} else {
Ok(Ok(crate::decode(&self.peek_buf).expect("only valid data here")))
})
}
}
}
use crate::{
borrowed::{Band, Text},
decode, MAX_DATA_LEN, MAX_LINE_LEN, U16_HEX_BYTES,
Expand Down Expand Up @@ -326,7 +211,7 @@ where
None => progress.set_name(progress_name(progress.name(), text)),
};
}
Band::Error(d) => progress.fail(progress_name(None, Text::from(d).0)),
Band::Error(d) => progress.fail(progress_name(None, Text::from(d).as_slice())),
};
}
None => {
Expand Down
17 changes: 10 additions & 7 deletions git-transport/src/client/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ use bstr::{BString, ByteVec};
use std::{io, net::TcpStream};

pub struct Connection<R, W> {
read: R,
write: W,
line_buf: Vec<u8>,
line_reader: git_packetline::Reader<R>,
path: BString,
virtual_host: Option<(String, Option<u16>)>,
protocol: Protocol,
Expand Down Expand Up @@ -58,14 +57,19 @@ where
self.virtual_host.as_ref(),
))?;
self.write.flush()?;
let mut rd = git_packetline::read::borrowed::Reader::new(&mut self.read, &mut self.line_buf, None);
let line = rd
let capabilities = self
.line_reader
.peek_line()
.ok_or(crate::client::Error::ExpectedLine("capabilities or version"))???;

Ok(SetServiceResponse {
actual_protocol: Protocol::V1, // TODO - read actual only if we are in version two or above
capabilities: Capabilities::try_from(&b"tbd"[..])?,
capabilities: Capabilities::try_from(
capabilities
.to_text()
.ok_or(crate::client::Error::ExpectedDataLine)?
.as_slice(),
)?,
refs: None, // TODO
})
}
Expand All @@ -84,9 +88,8 @@ where
virtual_host: Option<(impl Into<String>, Option<u16>)>,
) -> Self {
Connection {
read,
write,
line_buf: Vec::new(),
line_reader: git_packetline::Reader::new(read, None),
path: repository_path.into(),
virtual_host: virtual_host.map(|(h, p)| (h.into(), p)),
protocol: desired_version,
Expand Down
3 changes: 3 additions & 0 deletions git-transport/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ quick_error! {
ExpectedLine(message: &'static str) {
display("A {} line was expected, but there was none", message)
}
ExpectedDataLine {
display("Expected a data line, but got a delimiter")
}
}
}

Expand Down

0 comments on commit 633341d

Please sign in to comment.