aboutsummaryrefslogtreecommitdiffstats
path: root/src/loggable.rs
diff options
context:
space:
mode:
authorLibravatar cel 🌸 <cel@bunny.garden>2025-04-03 03:09:35 +0100
committerLibravatar cel 🌸 <cel@bunny.garden>2025-04-03 03:09:35 +0100
commit9c561014f3c4278c0991290c898713f8e9c928e8 (patch)
tree92c60a88b34909387c854c483a3c3f4bc41c27b9 /src/loggable.rs
parent2b399fb59d17bc127fbcd1533a3c079bc86770e1 (diff)
downloadpeanuts-9c561014f3c4278c0991290c898713f8e9c928e8.tar.gz
peanuts-9c561014f3c4278c0991290c898713f8e9c928e8.tar.bz2
peanuts-9c561014f3c4278c0991290c898713f8e9c928e8.zip
feat: xml logging
Diffstat (limited to 'src/loggable.rs')
-rw-r--r--src/loggable.rs67
1 files changed, 67 insertions, 0 deletions
diff --git a/src/loggable.rs b/src/loggable.rs
new file mode 100644
index 0000000..dd69668
--- /dev/null
+++ b/src/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)))
+ }
+}