aboutsummaryrefslogtreecommitdiffstats
path: root/src/writer
diff options
context:
space:
mode:
Diffstat (limited to 'src/writer')
-rw-r--r--src/writer/endable.rs37
-rw-r--r--src/writer/loggable.rs67
2 files changed, 104 insertions, 0 deletions
diff --git a/src/writer/endable.rs b/src/writer/endable.rs
new file mode 100644
index 0000000..6d842f3
--- /dev/null
+++ b/src/writer/endable.rs
@@ -0,0 +1,37 @@
+use crate::Error;
+
+#[derive(Debug)]
+pub struct Endable<T> {
+ inner: T,
+ ended: bool,
+}
+
+impl<T> Endable<T> {
+ pub fn new(inner: T) -> Self {
+ Self {
+ inner,
+ ended: false,
+ }
+ }
+
+ pub fn end(&mut self) {
+ self.ended = true;
+ }
+
+ pub fn into_inner(self) -> T {
+ self.inner
+ }
+
+ #[inline(always)]
+ pub fn try_as_mut(&mut self) -> Result<&mut T, Error> {
+ if self.ended {
+ Err(Error::RootElementEnded)
+ } else {
+ Ok(&mut self.inner)
+ }
+ }
+
+ pub fn ignore_end(&mut self) -> &mut T {
+ &mut self.inner
+ }
+}
diff --git a/src/writer/loggable.rs b/src/writer/loggable.rs
new file mode 100644
index 0000000..dd69668
--- /dev/null
+++ b/src/writer/loggable.rs
@@ -0,0 +1,67 @@
+use std::{fmt::Display, mem, pin::pin, task::Poll};
+
+use futures::ready;
+use pin_project::pin_project;
+pub use tokio::io::AsyncWrite;
+
+#[pin_project]
+#[derive(Debug)]
+pub struct Loggable<W> {
+ log_buffer: Vec<u8>,
+ #[pin]
+ writer: W,
+}
+
+impl<W> Loggable<W> {
+ pub fn new(writer: W) -> Self {
+ Self {
+ log_buffer: Vec::new(),
+ writer,
+ }
+ }
+
+ pub fn into_inner(self) -> W {
+ self.writer
+ }
+
+ pub fn take_log(&mut self) -> Vec<u8> {
+ let log: Vec<u8> = mem::replace(&mut self.log_buffer, Vec::new());
+ log
+ }
+}
+
+impl<W: AsyncWrite + Unpin + Send> Display for Loggable<W> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ let str = str::from_utf8(&self.log_buffer).unwrap_or("buffer to string conversion failed");
+ f.write_str(str)
+ }
+}
+
+impl<W: AsyncWrite + Unpin + Send> AsyncWrite for Loggable<W> {
+ fn poll_write(
+ mut self: std::pin::Pin<&mut Self>,
+ cx: &mut std::task::Context<'_>,
+ buf: &[u8],
+ ) -> std::task::Poll<Result<usize, std::io::Error>> {
+ let this = self.as_mut().project();
+ let ready = ready!(this.writer.poll_write(cx, buf));
+ self.log_buffer.extend_from_slice(buf);
+ Poll::Ready(ready)
+ }
+
+ fn poll_flush(
+ self: std::pin::Pin<&mut Self>,
+ cx: &mut std::task::Context<'_>,
+ ) -> std::task::Poll<Result<(), std::io::Error>> {
+ let this = self.project();
+ Poll::Ready(ready!(this.writer.poll_flush(cx)))
+ }
+
+ fn poll_shutdown(
+ self: std::pin::Pin<&mut Self>,
+ cx: &mut std::task::Context<'_>,
+ ) -> std::task::Poll<Result<(), std::io::Error>> {
+ let this = self.project();
+ Poll::Ready(ready!(this.writer.poll_shutdown(cx)))
+ }
+}