Skip to content

Commit

Permalink
[packetline #178] rename PacketLine to PacketLineRef…
Browse files Browse the repository at this point in the history
…and move it. Adjust location of decode-ref error.
  • Loading branch information
Byron committed Aug 26, 2021
1 parent ffd96f9 commit d4c16a9
Show file tree
Hide file tree
Showing 23 changed files with 168 additions and 157 deletions.
7 changes: 6 additions & 1 deletion git-packetline/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
### 0.10.0 (2021-08-??)

- TBD
#### Breaking

* **renames / moves**
- `immutable::PacketLine` -> `PacketLineRef`
- `immutable::DecodeBandError` -> `decode::band::Error`

36 changes: 27 additions & 9 deletions git-packetline/src/decode.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use bstr::BString;
use quick_error::quick_error;

use crate::{PacketLine, DELIMITER_LINE, FLUSH_LINE, MAX_DATA_LEN, MAX_LINE_LEN, RESPONSE_END_LINE, U16_HEX_BYTES};
use crate::{PacketLineRef, DELIMITER_LINE, FLUSH_LINE, MAX_DATA_LEN, MAX_LINE_LEN, RESPONSE_END_LINE, U16_HEX_BYTES};

quick_error! {
/// The error used in the [`decode`][crate::decode] module
Expand Down Expand Up @@ -29,13 +29,31 @@ quick_error! {
}
}

///
pub mod band {
use quick_error::quick_error;
quick_error! {
/// The error used in [`PacketLineRef::decode_band()`].
#[derive(Debug)]
#[allow(missing_docs)]
pub enum Error {
InvalidSideBand(band: u8) {
display("attempt to decode a non-side channel line or input was malformed: {}", band)
}
NonDataLine {
display("attempt to decode a non-data line into a side-channel band")
}
}
}
}

/// A utility return type to support incremental parsing of packet lines.
#[derive(Debug, Clone)]
pub enum Stream<'a> {
/// Indicate a single packet line was parsed completely
Complete {
/// The parsed packet line
line: PacketLine<'a>,
line: PacketLineRef<'a>,
/// The amount of bytes consumed from input
bytes_consumed: usize,
},
Expand All @@ -49,7 +67,7 @@ pub enum Stream<'a> {
/// The result of [`hex_prefix()`] indicating either a special packet line or the amount of wanted bytes
pub enum PacketLineOrWantedSize<'a> {
/// The special kind of packet line decoded from the hex prefix. It never contains actual data.
Line(PacketLine<'a>),
Line(PacketLineRef<'a>),
/// The amount of bytes indicated by the hex prefix of the packet line.
Wanted(u16),
}
Expand All @@ -58,9 +76,9 @@ pub enum PacketLineOrWantedSize<'a> {
pub fn hex_prefix(four_bytes: &[u8]) -> Result<PacketLineOrWantedSize<'_>, Error> {
debug_assert_eq!(four_bytes.len(), 4, "need four hex bytes");
for (line_bytes, line_type) in &[
(FLUSH_LINE, PacketLine::Flush),
(DELIMITER_LINE, PacketLine::Delimiter),
(RESPONSE_END_LINE, PacketLine::ResponseEnd),
(FLUSH_LINE, PacketLineRef::Flush),
(DELIMITER_LINE, PacketLineRef::Delimiter),
(RESPONSE_END_LINE, PacketLineRef::ResponseEnd),
] {
if four_bytes == *line_bytes {
return Ok(PacketLineOrWantedSize::Line(*line_type));
Expand All @@ -85,12 +103,12 @@ pub fn hex_prefix(four_bytes: &[u8]) -> Result<PacketLineOrWantedSize<'_>, Error
}

/// Obtain a `PacketLine` from `data` after assuring `data` is small enough to fit.
pub fn to_data_line(data: &[u8]) -> Result<PacketLine<'_>, Error> {
pub fn to_data_line(data: &[u8]) -> Result<PacketLineRef<'_>, Error> {
if data.len() > MAX_LINE_LEN {
return Err(Error::DataLengthLimitExceeded(data.len()));
}

Ok(PacketLine::Data(data))
Ok(PacketLineRef::Data(data))
}

/// Decode `data` as packet line while reporting whether the data is complete or not using a [`Stream`].
Expand Down Expand Up @@ -129,7 +147,7 @@ pub fn streaming(data: &[u8]) -> Result<Stream<'_>, Error> {
///
/// Note that failure also happens if there is not enough data to parse a complete packet line, as opposed to [`streaming()`] decoding
/// succeeds in that case, stating how much more bytes are required.
pub fn all_at_once(data: &[u8]) -> Result<PacketLine<'_>, Error> {
pub fn all_at_once(data: &[u8]) -> Result<PacketLineRef<'_>, Error> {
match streaming(data)? {
Stream::Complete { line, .. } => Ok(line),
Stream::Incomplete { bytes_needed } => Err(Error::NotEnoughData(bytes_needed)),
Expand Down
12 changes: 6 additions & 6 deletions git-packetline/src/immutable/async_io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use futures_io::AsyncWrite;
use crate::{
encode,
immutable::{Band, Error, Text},
Channel, PacketLine,
Channel, PacketLineRef,
};

impl<'a> Band<'a> {
Expand Down Expand Up @@ -38,14 +38,14 @@ impl<'a> Error<'a> {
}
}

impl<'a> PacketLine<'a> {
impl<'a> PacketLineRef<'a> {
/// Serialize this instance to `out` in git `packetline` format, returning the amount of bytes written to `out`.
pub async fn write_to(&self, out: impl AsyncWrite + Unpin) -> io::Result<usize> {
match self {
PacketLine::Data(d) => encode::data_to_write(d, out).await,
PacketLine::Flush => encode::flush_to_write(out).await,
PacketLine::Delimiter => encode::delim_to_write(out).await,
PacketLine::ResponseEnd => encode::response_end_to_write(out).await,
PacketLineRef::Data(d) => encode::data_to_write(d, out).await,
PacketLineRef::Flush => encode::flush_to_write(out).await,
PacketLineRef::Delimiter => encode::delim_to_write(out).await,
PacketLineRef::ResponseEnd => encode::response_end_to_write(out).await,
}
}
}
12 changes: 6 additions & 6 deletions git-packetline/src/immutable/blocking_io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::io;
use crate::{
encode,
immutable::{Band, Error, Text},
Channel, PacketLine,
Channel, PacketLineRef,
};

impl<'a> Band<'a> {
Expand Down Expand Up @@ -35,14 +35,14 @@ impl<'a> Error<'a> {
}
}

impl<'a> PacketLine<'a> {
impl<'a> PacketLineRef<'a> {
/// Serialize this instance to `out` in git `packetline` format, returning the amount of bytes written to `out`.
pub fn write_to(&self, out: impl io::Write) -> io::Result<usize> {
match self {
PacketLine::Data(d) => encode::data_to_write(d, out),
PacketLine::Flush => encode::flush_to_write(out),
PacketLine::Delimiter => encode::delim_to_write(out),
PacketLine::ResponseEnd => encode::response_end_to_write(out),
PacketLineRef::Data(d) => encode::data_to_write(d, out),
PacketLineRef::Flush => encode::flush_to_write(out),
PacketLineRef::Delimiter => encode::delim_to_write(out),
PacketLineRef::ResponseEnd => encode::response_end_to_write(out),
}
}
}
43 changes: 7 additions & 36 deletions git-packetline/src/immutable/mod.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,13 @@
use bstr::BStr;

use crate::{Channel, ERR_PREFIX};
use crate::{decode, Channel, PacketLineRef, ERR_PREFIX};

/// A borrowed packet line as it refers to a slice of data by reference.
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
pub enum PacketLine<'a> {
/// A chunk of raw data.
Data(&'a [u8]),
/// A flush packet.
Flush,
/// A delimiter packet.
Delimiter,
/// The end of the response.
ResponseEnd,
}

impl<'a> PacketLine<'a> {
impl<'a> PacketLineRef<'a> {
/// Return this instance as slice if it's [`Data`][PacketLine::Data].
pub fn as_slice(&self) -> Option<&[u8]> {
match self {
PacketLine::Data(d) => Some(d),
PacketLine::Flush | PacketLine::Delimiter | PacketLine::ResponseEnd => None,
PacketLineRef::Data(d) => Some(d),
PacketLineRef::Flush | PacketLineRef::Delimiter | PacketLineRef::ResponseEnd => None,
}
}
/// Return this instance's [`as_slice()`][PacketLine::as_slice()] as [`BStr`].
Expand Down Expand Up @@ -67,32 +53,17 @@ impl<'a> PacketLine<'a> {
}

/// Decode the band of this [`slice`][PacketLine::as_slice()], or panic if it is not actually a side-band line.
pub fn decode_band(&self) -> Result<Band<'_>, DecodeBandError> {
let d = self.as_slice().ok_or(DecodeBandError::NonDataLine)?;
pub fn decode_band(&self) -> Result<Band<'_>, decode::band::Error> {
let d = self.as_slice().ok_or(decode::band::Error::NonDataLine)?;
Ok(match d[0] {
1 => Band::Data(&d[1..]),
2 => Band::Progress(&d[1..]),
3 => Band::Error(&d[1..]),
band => return Err(DecodeBandError::InvalidSideBand(band)),
band => return Err(decode::band::Error::InvalidSideBand(band)),
})
}
}

use quick_error::quick_error;
quick_error! {
/// The error used in [`decode_band()`][PacketLine::decode_band()].
#[derive(Debug)]
#[allow(missing_docs)]
pub enum DecodeBandError {
InvalidSideBand(band: u8) {
display("attempt to decode a non-side channel line or input was malformed: {}", band)
}
NonDataLine {
display("attempt to decode a non-data line into a side-channel band")
}
}
}

/// A packet line representing an Error in a side-band channel.
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
Expand Down
14 changes: 13 additions & 1 deletion git-packetline/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,19 @@ pub enum Channel {

///
pub mod immutable;
pub use immutable::PacketLine;
/// A borrowed packet line as it refers to a slice of data by reference.
#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)]
#[cfg_attr(feature = "serde1", derive(serde::Serialize, serde::Deserialize))]
pub enum PacketLineRef<'a> {
/// A chunk of raw data.
Data(&'a [u8]),
/// A flush packet.
Flush,
/// A delimiter packet.
Delimiter,
/// The end of the response.
ResponseEnd,
}

///
pub mod read;
Expand Down
10 changes: 5 additions & 5 deletions git-packetline/src/read/async_io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use futures_lite::AsyncReadExt;
use crate::{
decode,
read::{ExhaustiveOutcome, WithSidebands},
PacketLine, StreamingPeekableIter, MAX_LINE_LEN, U16_HEX_BYTES,
PacketLineRef, StreamingPeekableIter, MAX_LINE_LEN, U16_HEX_BYTES,
};

/// Non-IO methods
Expand All @@ -19,7 +19,7 @@ where
async fn read_line_inner<'a>(
reader: &mut T,
buf: &'a mut Vec<u8>,
) -> io::Result<Result<PacketLine<'a>, decode::Error>> {
) -> io::Result<Result<PacketLineRef<'a>, decode::Error>> {
let (hex_bytes, data_bytes) = buf.split_at_mut(4);
reader.read_exact(hex_bytes).await?;
let num_data_bytes = match decode::hex_prefix(hex_bytes) {
Expand All @@ -41,7 +41,7 @@ where
async fn read_line_inner_exhaustive<'a>(
reader: &mut T,
buf: &'a mut Vec<u8>,
delimiters: &[PacketLine<'static>],
delimiters: &[PacketLineRef<'static>],
fail_on_err_lines: bool,
buf_resize: bool,
) -> ExhaustiveOutcome<'a> {
Expand Down Expand Up @@ -89,7 +89,7 @@ where
/// * natural EOF
/// * ERR packet line encountered if [`fail_on_err_lines()`][StreamingPeekableIter::fail_on_err_lines()] is true.
/// * A `delimiter` packet line encountered
pub async fn read_line(&mut self) -> Option<io::Result<Result<PacketLine<'_>, decode::Error>>> {
pub async fn read_line(&mut self) -> Option<io::Result<Result<PacketLineRef<'_>, decode::Error>>> {
if self.is_done {
return None;
}
Expand Down Expand Up @@ -118,7 +118,7 @@ where
/// Peek the next packet line without consuming it.
///
/// Multiple calls to peek will return the same packet line, if there is one.
pub async fn peek_line(&mut self) -> Option<io::Result<Result<PacketLine<'_>, decode::Error>>> {
pub async fn peek_line(&mut self) -> Option<io::Result<Result<PacketLineRef<'_>, decode::Error>>> {
if self.is_done {
return None;
}
Expand Down
13 changes: 8 additions & 5 deletions git-packetline/src/read/blocking_io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,18 @@ use bstr::ByteSlice;
use crate::{
decode,
read::{ExhaustiveOutcome, WithSidebands},
PacketLine, StreamingPeekableIter, MAX_LINE_LEN, U16_HEX_BYTES,
PacketLineRef, StreamingPeekableIter, MAX_LINE_LEN, U16_HEX_BYTES,
};

/// Non-IO methods
impl<T> StreamingPeekableIter<T>
where
T: io::Read,
{
fn read_line_inner<'a>(reader: &mut T, buf: &'a mut Vec<u8>) -> io::Result<Result<PacketLine<'a>, decode::Error>> {
fn read_line_inner<'a>(
reader: &mut T,
buf: &'a mut Vec<u8>,
) -> io::Result<Result<PacketLineRef<'a>, 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) {
Expand All @@ -35,7 +38,7 @@ where
fn read_line_inner_exhaustive<'a>(
reader: &mut T,
buf: &'a mut Vec<u8>,
delimiters: &[PacketLine<'static>],
delimiters: &[PacketLineRef<'static>],
fail_on_err_lines: bool,
buf_resize: bool,
) -> ExhaustiveOutcome<'a> {
Expand Down Expand Up @@ -83,7 +86,7 @@ where
/// * natural EOF
/// * ERR packet line encountered if [`fail_on_err_lines()`][StreamingPeekableIter::fail_on_err_lines()] is true.
/// * A `delimiter` packet line encountered
pub fn read_line(&mut self) -> Option<io::Result<Result<PacketLine<'_>, decode::Error>>> {
pub fn read_line(&mut self) -> Option<io::Result<Result<PacketLineRef<'_>, decode::Error>>> {
if self.is_done {
return None;
}
Expand Down Expand Up @@ -111,7 +114,7 @@ where
/// Peek the next packet line without consuming it.
///
/// Multiple calls to peek will return the same packet line, if there is one.
pub fn peek_line(&mut self) -> Option<io::Result<Result<PacketLine<'_>, decode::Error>>> {
pub fn peek_line(&mut self) -> Option<io::Result<Result<PacketLineRef<'_>, decode::Error>>> {
if self.is_done {
return None;
}
Expand Down
18 changes: 9 additions & 9 deletions git-packetline/src/read/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
#[cfg(any(feature = "blocking-io", feature = "async-io"))]
use crate::MAX_LINE_LEN;
use crate::{PacketLine, U16_HEX_BYTES};
use crate::{PacketLineRef, U16_HEX_BYTES};

#[cfg(any(feature = "blocking-io", feature = "async-io"))]
type ExhaustiveOutcome<'a> = (
bool, // is_done
Option<PacketLine<'static>>, // stopped_at
Option<std::io::Result<Result<PacketLine<'a>, crate::decode::Error>>>, // actual method result
bool, // is_done
Option<PacketLineRef<'static>>, // stopped_at
Option<std::io::Result<Result<PacketLineRef<'a>, crate::decode::Error>>>, // actual method result
);

/// Read pack lines one after another, without consuming more than needed from the underlying
Expand All @@ -20,14 +20,14 @@ pub struct StreamingPeekableIter<T> {
#[cfg(any(feature = "blocking-io", feature = "async-io"))]
buf: Vec<u8>,
fail_on_err_lines: bool,
delimiters: &'static [PacketLine<'static>],
delimiters: &'static [PacketLineRef<'static>],
is_done: bool,
stopped_at: Option<PacketLine<'static>>,
stopped_at: Option<PacketLineRef<'static>>,
}

impl<T> StreamingPeekableIter<T> {
/// Return a new instance from `read` which will stop decoding packet lines when receiving one of the given `delimiters`.
pub fn new(read: T, delimiters: &'static [PacketLine<'static>]) -> Self {
pub fn new(read: T, delimiters: &'static [PacketLineRef<'static>]) -> Self {
StreamingPeekableIter {
read,
#[cfg(any(feature = "blocking-io", feature = "async-io"))]
Expand Down Expand Up @@ -58,7 +58,7 @@ impl<T> StreamingPeekableIter<T> {

/// Returns the packet line that stopped the iteration, or
/// `None` if the end wasn't reached yet, on EOF, or if [`fail_on_err_lines()`][StreamingPeekableIter::fail_on_err_lines()] was true.
pub fn stopped_at(&self) -> Option<PacketLine<'static>> {
pub fn stopped_at(&self) -> Option<PacketLineRef<'static>> {
self.stopped_at
}

Expand All @@ -71,7 +71,7 @@ impl<T> StreamingPeekableIter<T> {
}

/// Similar to [`reset()`][StreamingPeekableIter::reset()] with support to changing the `delimiters`.
pub fn reset_with(&mut self, delimiters: &'static [PacketLine<'static>]) {
pub fn reset_with(&mut self, delimiters: &'static [PacketLineRef<'static>]) {
self.delimiters = delimiters;
self.is_done = false;
self.stopped_at = None;
Expand Down
Loading

0 comments on commit d4c16a9

Please sign in to comment.