summaryrefslogtreecommitdiffstats
path: root/vendor/gix-packetline-blocking/src/write
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gix-packetline-blocking/src/write')
-rw-r--r--vendor/gix-packetline-blocking/src/write/async_io.rs97
-rw-r--r--vendor/gix-packetline-blocking/src/write/blocking_io.rs71
-rw-r--r--vendor/gix-packetline-blocking/src/write/mod.rs21
3 files changed, 189 insertions, 0 deletions
diff --git a/vendor/gix-packetline-blocking/src/write/async_io.rs b/vendor/gix-packetline-blocking/src/write/async_io.rs
new file mode 100644
index 000000000..19eaac16c
--- /dev/null
+++ b/vendor/gix-packetline-blocking/src/write/async_io.rs
@@ -0,0 +1,97 @@
+use std::{
+ io,
+ pin::Pin,
+ task::{Context, Poll},
+};
+
+use futures_io::AsyncWrite;
+
+use crate::{encode, MAX_DATA_LEN, U16_HEX_BYTES};
+
+pin_project_lite::pin_project! {
+ /// An implementor of [`Write`][io::Write] which passes all input to an inner `Write` in packet line data encoding,
+ /// one line per `write(…)` call or as many lines as it takes if the data doesn't fit into the maximum allowed line length.
+ pub struct Writer<T> {
+ #[pin]
+ inner: encode::LineWriter<'static, T>,
+ state: State,
+ }
+}
+
+enum State {
+ Idle,
+ WriteData(usize),
+}
+
+impl<T: AsyncWrite + Unpin> Writer<T> {
+ /// Create a new instance from the given `write`
+ pub fn new(write: T) -> Self {
+ Writer {
+ inner: encode::LineWriter::new(write, &[], &[]),
+ state: State::Idle,
+ }
+ }
+
+ /// Return the inner writer, consuming self.
+ pub fn into_inner(self) -> T {
+ self.inner.into_inner()
+ }
+
+ /// Return a mutable reference to the inner writer, useful if packet lines should be serialized directly.
+ pub fn inner_mut(&mut self) -> &mut T {
+ &mut self.inner.writer
+ }
+}
+
+/// Non-IO methods
+impl<T> Writer<T> {
+ /// If called, each call to [`write()`][io::Write::write()] will write bytes as is.
+ pub fn enable_binary_mode(&mut self) {
+ self.inner.suffix = &[];
+ }
+ /// If called, each call to [`write()`][io::Write::write()] will write the input as text, appending a trailing newline
+ /// if needed before writing.
+ pub fn enable_text_mode(&mut self) {
+ self.inner.suffix = &[b'\n'];
+ }
+}
+
+impl<T: AsyncWrite + Unpin> AsyncWrite for Writer<T> {
+ fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {
+ let mut this = self.project();
+ loop {
+ match this.state {
+ State::Idle => {
+ if buf.is_empty() {
+ return Poll::Ready(Err(io::Error::new(
+ io::ErrorKind::Other,
+ "empty packet lines are not permitted as '0004' is invalid",
+ )));
+ }
+ *this.state = State::WriteData(0)
+ }
+ State::WriteData(written) => {
+ while *written != buf.len() {
+ let data = &buf[*written..*written + (buf.len() - *written).min(MAX_DATA_LEN)];
+ let n = futures_lite::ready!(this.inner.as_mut().poll_write(cx, data))?;
+ if n == 0 {
+ return Poll::Ready(Err(io::ErrorKind::WriteZero.into()));
+ }
+ *written += n;
+ *written -= U16_HEX_BYTES + this.inner.suffix.len();
+ }
+ *this.state = State::Idle;
+ return Poll::Ready(Ok(buf.len()));
+ }
+ }
+ }
+ }
+
+ fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
+ self.project().inner.poll_flush(cx)
+ }
+
+ fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
+ self.project().inner.poll_close(cx)
+ }
+}
diff --git a/vendor/gix-packetline-blocking/src/write/blocking_io.rs b/vendor/gix-packetline-blocking/src/write/blocking_io.rs
new file mode 100644
index 000000000..d537d7ddf
--- /dev/null
+++ b/vendor/gix-packetline-blocking/src/write/blocking_io.rs
@@ -0,0 +1,71 @@
+use std::io;
+
+use crate::{MAX_DATA_LEN, U16_HEX_BYTES};
+
+/// An implementor of [`Write`][io::Write] which passes all input to an inner `Write` in packet line data encoding,
+/// one line per `write(…)` call or as many lines as it takes if the data doesn't fit into the maximum allowed line length.
+pub struct Writer<T> {
+ /// the `Write` implementation to which to propagate packet lines
+ inner: T,
+ binary: bool,
+}
+
+impl<T: io::Write> Writer<T> {
+ /// Create a new instance from the given `write`
+ pub fn new(write: T) -> Self {
+ Writer {
+ inner: write,
+ binary: true,
+ }
+ }
+}
+
+/// Non-IO methods
+impl<T> Writer<T> {
+ /// If called, each call to [`write()`][io::Write::write()] will write bytes as is.
+ pub fn enable_binary_mode(&mut self) {
+ self.binary = true;
+ }
+ /// If called, each call to [`write()`][io::Write::write()] will write the input as text, appending a trailing newline
+ /// if needed before writing.
+ pub fn enable_text_mode(&mut self) {
+ self.binary = false;
+ }
+ /// Return the inner writer, consuming self.
+ pub fn into_inner(self) -> T {
+ self.inner
+ }
+ /// Return a mutable reference to the inner writer, useful if packet lines should be serialized directly.
+ pub fn inner_mut(&mut self) -> &mut T {
+ &mut self.inner
+ }
+}
+
+impl<T: io::Write> io::Write for Writer<T> {
+ fn write(&mut self, mut buf: &[u8]) -> io::Result<usize> {
+ if buf.is_empty() {
+ return Err(io::Error::new(
+ io::ErrorKind::Other,
+ "empty packet lines are not permitted as '0004' is invalid",
+ ));
+ }
+
+ let mut written = 0;
+ while !buf.is_empty() {
+ let (data, rest) = buf.split_at(buf.len().min(MAX_DATA_LEN));
+ written += if self.binary {
+ crate::encode::data_to_write(data, &mut self.inner)
+ } else {
+ crate::encode::text_to_write(data, &mut self.inner)
+ }?;
+ // subtract header (and trailing NL) because write-all can't handle writing more than it passes in
+ written -= U16_HEX_BYTES + usize::from(!self.binary);
+ buf = rest;
+ }
+ Ok(written)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ self.inner.flush()
+ }
+}
diff --git a/vendor/gix-packetline-blocking/src/write/mod.rs b/vendor/gix-packetline-blocking/src/write/mod.rs
new file mode 100644
index 000000000..f40a6bdae
--- /dev/null
+++ b/vendor/gix-packetline-blocking/src/write/mod.rs
@@ -0,0 +1,21 @@
+use crate::Writer;
+
+#[cfg(all(not(feature = "blocking-io"), feature = "async-io"))]
+pub(crate) mod async_io;
+
+#[cfg(feature = "blocking-io")]
+pub(crate) mod blocking_io;
+
+/// Common methods
+impl<T> Writer<T> {
+ /// As [`enable_text_mode()`][Writer::enable_text_mode()], but suitable for chaining.
+ pub fn text_mode(mut self) -> Self {
+ self.enable_text_mode();
+ self
+ }
+ /// As [`enable_binary_mode()`][Writer::enable_binary_mode()], but suitable for chaining.
+ pub fn binary_mode(mut self) -> Self {
+ self.enable_binary_mode();
+ self
+ }
+}