Skip to content

Commit a793bde

Browse files
committed
Replace gix-packetline-blocking/src with generated files
These are copies, except for their headers, and generated by the etc/copy-packetline.sh script. This should make the new CI checks, which use the script, pass.
1 parent ac35cfc commit a793bde

File tree

18 files changed

+2095
-1
lines changed

18 files changed

+2095
-1
lines changed

gix-packetline-blocking/src

Lines changed: 0 additions & 1 deletion
This file was deleted.

gix-packetline-blocking/src/decode.rs

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
//! DO NOT EDIT - this is a copy of gix-packetline/src/decode.rs. Run `just copy-packetline` to update it.
2+
3+
use bstr::BString;
4+
5+
use crate::{PacketLineRef, DELIMITER_LINE, FLUSH_LINE, MAX_DATA_LEN, MAX_LINE_LEN, RESPONSE_END_LINE, U16_HEX_BYTES};
6+
7+
/// The error used in the [`decode`][mod@crate::decode] module
8+
#[derive(Debug, thiserror::Error)]
9+
#[allow(missing_docs)]
10+
pub enum Error {
11+
#[error("Failed to decode the first four hex bytes indicating the line length: {err}")]
12+
HexDecode { err: String },
13+
#[error("The data received claims to be larger than the maximum allowed size: got {length_in_bytes}, exceeds {MAX_DATA_LEN}")]
14+
DataLengthLimitExceeded { length_in_bytes: usize },
15+
#[error("Received an invalid empty line")]
16+
DataIsEmpty,
17+
#[error("Received an invalid line of length 3")]
18+
InvalidLineLength,
19+
#[error("{data:?} - consumed {bytes_consumed} bytes")]
20+
Line { data: BString, bytes_consumed: usize },
21+
#[error("Needing {bytes_needed} additional bytes to decode the line successfully")]
22+
NotEnoughData { bytes_needed: usize },
23+
}
24+
25+
///
26+
#[allow(clippy::empty_docs)]
27+
pub mod band {
28+
/// The error used in [`PacketLineRef::decode_band()`][super::PacketLineRef::decode_band()].
29+
#[derive(Debug, thiserror::Error)]
30+
#[allow(missing_docs)]
31+
pub enum Error {
32+
#[error("attempt to decode a non-side channel line or input was malformed: {band_id}")]
33+
InvalidSideBand { band_id: u8 },
34+
#[error("attempt to decode a non-data line into a side-channel band")]
35+
NonDataLine,
36+
}
37+
}
38+
39+
/// A utility return type to support incremental parsing of packet lines.
40+
#[derive(Debug, Clone)]
41+
pub enum Stream<'a> {
42+
/// Indicate a single packet line was parsed completely
43+
Complete {
44+
/// The parsed packet line
45+
line: PacketLineRef<'a>,
46+
/// The amount of bytes consumed from input
47+
bytes_consumed: usize,
48+
},
49+
/// A packet line could not yet be parsed due to missing bytes
50+
Incomplete {
51+
/// The amount of additional bytes needed for the parsing to complete
52+
bytes_needed: usize,
53+
},
54+
}
55+
56+
/// The result of [`hex_prefix()`] indicating either a special packet line or the amount of wanted bytes
57+
pub enum PacketLineOrWantedSize<'a> {
58+
/// The special kind of packet line decoded from the hex prefix. It never contains actual data.
59+
Line(PacketLineRef<'a>),
60+
/// The amount of bytes indicated by the hex prefix of the packet line.
61+
Wanted(u16),
62+
}
63+
64+
/// Decode the `four_bytes` packet line prefix provided in hexadecimal form and check it for validity.
65+
pub fn hex_prefix(four_bytes: &[u8]) -> Result<PacketLineOrWantedSize<'_>, Error> {
66+
debug_assert_eq!(four_bytes.len(), 4, "need four hex bytes");
67+
for (line_bytes, line_type) in &[
68+
(FLUSH_LINE, PacketLineRef::Flush),
69+
(DELIMITER_LINE, PacketLineRef::Delimiter),
70+
(RESPONSE_END_LINE, PacketLineRef::ResponseEnd),
71+
] {
72+
if four_bytes == *line_bytes {
73+
return Ok(PacketLineOrWantedSize::Line(*line_type));
74+
}
75+
}
76+
77+
let mut buf = [0u8; U16_HEX_BYTES / 2];
78+
faster_hex::hex_decode(four_bytes, &mut buf).map_err(|err| Error::HexDecode { err: err.to_string() })?;
79+
let wanted_bytes = u16::from_be_bytes(buf);
80+
81+
if wanted_bytes == 3 {
82+
return Err(Error::InvalidLineLength);
83+
}
84+
if wanted_bytes == 4 {
85+
return Err(Error::DataIsEmpty);
86+
}
87+
debug_assert!(
88+
wanted_bytes as usize > U16_HEX_BYTES,
89+
"by now there should be more wanted bytes than prefix bytes"
90+
);
91+
Ok(PacketLineOrWantedSize::Wanted(wanted_bytes - U16_HEX_BYTES as u16))
92+
}
93+
94+
/// Obtain a `PacketLine` from `data` after assuring `data` is small enough to fit.
95+
pub fn to_data_line(data: &[u8]) -> Result<PacketLineRef<'_>, Error> {
96+
if data.len() > MAX_LINE_LEN {
97+
return Err(Error::DataLengthLimitExceeded {
98+
length_in_bytes: data.len(),
99+
});
100+
}
101+
102+
Ok(PacketLineRef::Data(data))
103+
}
104+
105+
/// Decode `data` as packet line while reporting whether the data is complete or not using a [`Stream`].
106+
pub fn streaming(data: &[u8]) -> Result<Stream<'_>, Error> {
107+
let data_len = data.len();
108+
if data_len < U16_HEX_BYTES {
109+
return Ok(Stream::Incomplete {
110+
bytes_needed: U16_HEX_BYTES - data_len,
111+
});
112+
}
113+
let wanted_bytes = match hex_prefix(&data[..U16_HEX_BYTES])? {
114+
PacketLineOrWantedSize::Wanted(s) => s as usize,
115+
PacketLineOrWantedSize::Line(line) => {
116+
return Ok(Stream::Complete {
117+
line,
118+
bytes_consumed: 4,
119+
})
120+
}
121+
} + U16_HEX_BYTES;
122+
if wanted_bytes > MAX_LINE_LEN {
123+
return Err(Error::DataLengthLimitExceeded {
124+
length_in_bytes: wanted_bytes,
125+
});
126+
}
127+
if data_len < wanted_bytes {
128+
return Ok(Stream::Incomplete {
129+
bytes_needed: wanted_bytes - data_len,
130+
});
131+
}
132+
133+
Ok(Stream::Complete {
134+
line: to_data_line(&data[U16_HEX_BYTES..wanted_bytes])?,
135+
bytes_consumed: wanted_bytes,
136+
})
137+
}
138+
139+
/// Decode an entire packet line from data or fail.
140+
///
141+
/// Note that failure also happens if there is not enough data to parse a complete packet line, as opposed to [`streaming()`] decoding
142+
/// succeeds in that case, stating how much more bytes are required.
143+
pub fn all_at_once(data: &[u8]) -> Result<PacketLineRef<'_>, Error> {
144+
match streaming(data)? {
145+
Stream::Complete { line, .. } => Ok(line),
146+
Stream::Incomplete { bytes_needed } => Err(Error::NotEnoughData { bytes_needed }),
147+
}
148+
}
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
//! DO NOT EDIT - this is a copy of gix-packetline/src/encode/async_io.rs. Run `just copy-packetline` to update it.
2+
3+
use std::{
4+
io,
5+
pin::Pin,
6+
task::{Context, Poll},
7+
};
8+
9+
use futures_io::AsyncWrite;
10+
use futures_lite::AsyncWriteExt;
11+
12+
use super::u16_to_hex;
13+
use crate::{encode::Error, Channel, DELIMITER_LINE, ERR_PREFIX, FLUSH_LINE, MAX_DATA_LEN, RESPONSE_END_LINE};
14+
15+
pin_project_lite::pin_project! {
16+
/// A way of writing packet lines asynchronously.
17+
pub struct LineWriter<'a, W> {
18+
#[pin]
19+
pub(crate) writer: W,
20+
pub(crate) prefix: &'a [u8],
21+
pub(crate) suffix: &'a [u8],
22+
state: State<'a>,
23+
}
24+
}
25+
26+
enum State<'a> {
27+
Idle,
28+
WriteHexLen([u8; 4], usize),
29+
WritePrefix(&'a [u8]),
30+
WriteData(usize),
31+
WriteSuffix(&'a [u8]),
32+
}
33+
34+
impl<'a, W: AsyncWrite + Unpin> LineWriter<'a, W> {
35+
/// Create a new line writer writing data with a `prefix` and `suffix`.
36+
///
37+
/// Keep the additional `prefix` or `suffix` buffers empty if no prefix or suffix should be written.
38+
pub fn new(writer: W, prefix: &'a [u8], suffix: &'a [u8]) -> Self {
39+
LineWriter {
40+
writer,
41+
prefix,
42+
suffix,
43+
state: State::Idle,
44+
}
45+
}
46+
47+
/// Consume self and reveal the inner writer.
48+
pub fn into_inner(self) -> W {
49+
self.writer
50+
}
51+
}
52+
53+
fn into_io_err(err: Error) -> io::Error {
54+
io::Error::new(io::ErrorKind::Other, err)
55+
}
56+
57+
impl<W: AsyncWrite + Unpin> AsyncWrite for LineWriter<'_, W> {
58+
fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, data: &[u8]) -> Poll<io::Result<usize>> {
59+
use futures_lite::ready;
60+
let mut this = self.project();
61+
loop {
62+
match &mut this.state {
63+
State::Idle => {
64+
let data_len = this.prefix.len() + data.len() + this.suffix.len();
65+
if data_len > MAX_DATA_LEN {
66+
return Poll::Ready(Err(into_io_err(Error::DataLengthLimitExceeded {
67+
length_in_bytes: data_len,
68+
})));
69+
}
70+
if data.is_empty() {
71+
return Poll::Ready(Err(into_io_err(Error::DataIsEmpty)));
72+
}
73+
let data_len = data_len + 4;
74+
let len_buf = u16_to_hex(data_len as u16);
75+
*this.state = State::WriteHexLen(len_buf, 0)
76+
}
77+
State::WriteHexLen(hex_len, written) => {
78+
while *written != hex_len.len() {
79+
let n = ready!(this.writer.as_mut().poll_write(cx, &hex_len[*written..]))?;
80+
if n == 0 {
81+
return Poll::Ready(Err(io::ErrorKind::WriteZero.into()));
82+
}
83+
*written += n;
84+
}
85+
if this.prefix.is_empty() {
86+
*this.state = State::WriteData(0)
87+
} else {
88+
*this.state = State::WritePrefix(this.prefix)
89+
}
90+
}
91+
State::WritePrefix(buf) => {
92+
while !buf.is_empty() {
93+
let n = ready!(this.writer.as_mut().poll_write(cx, buf))?;
94+
if n == 0 {
95+
return Poll::Ready(Err(io::ErrorKind::WriteZero.into()));
96+
}
97+
let (_, rest) = std::mem::take(buf).split_at(n);
98+
*buf = rest;
99+
}
100+
*this.state = State::WriteData(0)
101+
}
102+
State::WriteData(written) => {
103+
while *written != data.len() {
104+
let n = ready!(this.writer.as_mut().poll_write(cx, &data[*written..]))?;
105+
if n == 0 {
106+
return Poll::Ready(Err(io::ErrorKind::WriteZero.into()));
107+
}
108+
*written += n;
109+
}
110+
if this.suffix.is_empty() {
111+
let written = 4 + this.prefix.len() + *written;
112+
*this.state = State::Idle;
113+
return Poll::Ready(Ok(written));
114+
} else {
115+
*this.state = State::WriteSuffix(this.suffix)
116+
}
117+
}
118+
State::WriteSuffix(buf) => {
119+
while !buf.is_empty() {
120+
let n = ready!(this.writer.as_mut().poll_write(cx, buf))?;
121+
if n == 0 {
122+
return Poll::Ready(Err(io::ErrorKind::WriteZero.into()));
123+
}
124+
let (_, rest) = std::mem::take(buf).split_at(n);
125+
*buf = rest;
126+
}
127+
*this.state = State::Idle;
128+
return Poll::Ready(Ok(4 + this.prefix.len() + data.len() + this.suffix.len()));
129+
}
130+
}
131+
}
132+
}
133+
134+
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
135+
let this = self.project();
136+
this.writer.poll_flush(cx)
137+
}
138+
139+
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
140+
let this = self.project();
141+
this.writer.poll_close(cx)
142+
}
143+
}
144+
145+
async fn prefixed_and_suffixed_data_to_write(
146+
prefix: &[u8],
147+
data: &[u8],
148+
suffix: &[u8],
149+
mut out: impl AsyncWrite + Unpin,
150+
) -> io::Result<usize> {
151+
let data_len = prefix.len() + data.len() + suffix.len();
152+
if data_len > MAX_DATA_LEN {
153+
return Err(into_io_err(Error::DataLengthLimitExceeded {
154+
length_in_bytes: data_len,
155+
}));
156+
}
157+
if data.is_empty() {
158+
return Err(into_io_err(Error::DataIsEmpty));
159+
}
160+
161+
let data_len = data_len + 4;
162+
let buf = u16_to_hex(data_len as u16);
163+
164+
out.write_all(&buf).await?;
165+
if !prefix.is_empty() {
166+
out.write_all(prefix).await?;
167+
}
168+
out.write_all(data).await?;
169+
if !suffix.is_empty() {
170+
out.write_all(suffix).await?;
171+
}
172+
Ok(data_len)
173+
}
174+
175+
async fn prefixed_data_to_write(prefix: &[u8], data: &[u8], out: impl AsyncWrite + Unpin) -> io::Result<usize> {
176+
prefixed_and_suffixed_data_to_write(prefix, data, &[], out).await
177+
}
178+
179+
/// Write a `text` message to `out`, which is assured to end in a newline.
180+
pub async fn text_to_write(text: &[u8], out: impl AsyncWrite + Unpin) -> io::Result<usize> {
181+
prefixed_and_suffixed_data_to_write(&[], text, &[b'\n'], out).await
182+
}
183+
184+
/// Write a `data` message to `out`.
185+
pub async fn data_to_write(data: &[u8], out: impl AsyncWrite + Unpin) -> io::Result<usize> {
186+
prefixed_data_to_write(&[], data, out).await
187+
}
188+
189+
/// Write an error `message` to `out`.
190+
pub async fn error_to_write(message: &[u8], out: impl AsyncWrite + Unpin) -> io::Result<usize> {
191+
prefixed_data_to_write(ERR_PREFIX, message, out).await
192+
}
193+
194+
/// Write a response-end message to `out`.
195+
pub async fn response_end_to_write(mut out: impl AsyncWrite + Unpin) -> io::Result<usize> {
196+
out.write_all(RESPONSE_END_LINE).await?;
197+
Ok(4)
198+
}
199+
200+
/// Write a delim message to `out`.
201+
pub async fn delim_to_write(mut out: impl AsyncWrite + Unpin) -> io::Result<usize> {
202+
out.write_all(DELIMITER_LINE).await?;
203+
Ok(4)
204+
}
205+
206+
/// Write a flush message to `out`.
207+
pub async fn flush_to_write(mut out: impl AsyncWrite + Unpin) -> io::Result<usize> {
208+
out.write_all(FLUSH_LINE).await?;
209+
Ok(4)
210+
}
211+
212+
/// Write `data` of `kind` to `out` using side-band encoding.
213+
pub async fn band_to_write(kind: Channel, data: &[u8], out: impl AsyncWrite + Unpin) -> io::Result<usize> {
214+
prefixed_data_to_write(&[kind as u8], data, out).await
215+
}

0 commit comments

Comments
 (0)