From 75abbda2d386e03d154faf970a2b789fbea42786 Mon Sep 17 00:00:00 2001 From: Asish Kumar Date: Mon, 25 May 2026 08:42:27 +0530 Subject: [PATCH] feat(core): implement debug for readers and writers Add Debug implementations for Reader, Writer, and their futures adapters using existing operation context such as scheme, root, path, args, and options. Add focused tests for debug output and update trait assertions to cover the new Debug bounds. --- .../src/types/read/futures_async_reader.rs | 23 ++++++++++- core/core/src/types/read/reader.rs | 38 ++++++++++++++++++- .../src/types/write/futures_async_writer.rs | 10 ++++- core/core/src/types/write/writer.rs | 38 ++++++++++++++++++- 4 files changed, 104 insertions(+), 5 deletions(-) diff --git a/core/core/src/types/read/futures_async_reader.rs b/core/core/src/types/read/futures_async_reader.rs index a237d1bf577e..0fec8d01d4aa 100644 --- a/core/core/src/types/read/futures_async_reader.rs +++ b/core/core/src/types/read/futures_async_reader.rs @@ -54,6 +54,25 @@ pub struct FuturesAsyncReader { /// Safety: FuturesAsyncReader only exposes `&mut self` to the outside world, unsafe impl Sync for FuturesAsyncReader {} +impl std::fmt::Debug for FuturesAsyncReader { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let info = self.ctx.accessor().info(); + let root = info.root(); + + f.debug_struct("FuturesAsyncReader") + .field("scheme", &info.scheme()) + .field("root", &root) + .field("path", &self.ctx.path()) + .field("args", self.ctx.args()) + .field("options", self.ctx.options()) + .field("start", &self.start) + .field("end", &self.end) + .field("pos", &self.pos) + .field("buffered", &self.buf.len()) + .finish_non_exhaustive() + } +} + impl FuturesAsyncReader { /// NOTE: don't allow users to create FuturesAsyncReader directly. /// @@ -200,8 +219,10 @@ mod tests { OpReader::new(), )); - let v = FuturesAsyncReader::new(ctx, 4..8); + fn assert_reader_traits(_: &T) {} + let v = FuturesAsyncReader::new(ctx, 4..8); + assert_reader_traits(&v); let _: Box = Box::new(v); Ok(()) } diff --git a/core/core/src/types/read/reader.rs b/core/core/src/types/read/reader.rs index f54e604a16a6..279f2ce31089 100644 --- a/core/core/src/types/read/reader.rs +++ b/core/core/src/types/read/reader.rs @@ -93,6 +93,21 @@ pub struct Reader { ctx: Arc, } +impl std::fmt::Debug for Reader { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let info = self.ctx.accessor().info(); + let root = info.root(); + + f.debug_struct("Reader") + .field("scheme", &info.scheme()) + .field("root", &root) + .field("path", &self.ctx.path()) + .field("args", self.ctx.args()) + .field("options", self.ctx.options()) + .finish_non_exhaustive() + } +} + impl Reader { /// Create a new reader. /// @@ -452,7 +467,28 @@ mod tests { let acc = op.into_inner(); let ctx = ReadContext::new(acc, "test".to_string(), OpRead::new(), OpReader::new()); - let _: Box = Box::new(Reader::new(ctx)); + fn assert_reader_traits(_: &T) {} + + let reader = Reader::new(ctx); + assert_reader_traits(&reader); + let _: Box = Box::new(reader); + + Ok(()) + } + + #[tokio::test] + async fn test_debug() -> Result<()> { + let op = Operator::via_iter(services::MEMORY_SCHEME, [])?; + op.write("test", "hello").await?; + + let reader = op.reader_with("test").chunk(8).await?; + let output = format!("{reader:?}"); + + assert!(output.contains("Reader"), "{output}"); + assert!(output.contains("memory"), "{output}"); + assert!(output.contains("test"), "{output}"); + assert!(output.contains("args"), "{output}"); + assert!(output.contains("options"), "{output}"); Ok(()) } diff --git a/core/core/src/types/write/futures_async_writer.rs b/core/core/src/types/write/futures_async_writer.rs index 752a74d63ac1..e67af0e6a1e2 100644 --- a/core/core/src/types/write/futures_async_writer.rs +++ b/core/core/src/types/write/futures_async_writer.rs @@ -37,6 +37,12 @@ pub struct FuturesAsyncWriter { buf: oio::FlexBuf, } +impl std::fmt::Debug for FuturesAsyncWriter { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("FuturesAsyncWriter").finish_non_exhaustive() + } +} + impl FuturesAsyncWriter { /// NOTE: don't allow users to create directly. #[inline] @@ -129,8 +135,10 @@ mod tests { )); let write_gen = WriteGenerator::create(ctx).await.unwrap(); - let v = FuturesAsyncWriter::new(write_gen); + fn assert_writer_traits(_: &T) {} + let v = FuturesAsyncWriter::new(write_gen); + assert_writer_traits(&v); let _: Box = Box::new(v); } } diff --git a/core/core/src/types/write/writer.rs b/core/core/src/types/write/writer.rs index ae9c71837afc..4cb196dbd09b 100644 --- a/core/core/src/types/write/writer.rs +++ b/core/core/src/types/write/writer.rs @@ -99,17 +99,32 @@ use crate::*; /// creating writer with `append` enabled. pub struct Writer { /// Keep a reference to write context in writer. - _ctx: Arc, + ctx: Arc, inner: WriteGenerator, } +impl std::fmt::Debug for Writer { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let info = self.ctx.accessor().info(); + let root = info.root(); + + f.debug_struct("Writer") + .field("scheme", &info.scheme()) + .field("root", &root) + .field("path", &self.ctx.path()) + .field("args", self.ctx.args()) + .field("options", self.ctx.options()) + .finish_non_exhaustive() + } +} + impl Writer { /// Create a new writer from an `oio::Writer`. pub(crate) async fn new(ctx: WriteContext) -> Result { let ctx = Arc::new(ctx); let inner = WriteGenerator::create(ctx.clone()).await?; - Ok(Self { _ctx: ctx, inner }) + Ok(Self { ctx, inner }) } /// Write [`Buffer`] into writer. @@ -383,6 +398,7 @@ mod tests { use rand::{Rng, RngExt}; use crate::Operator; + use crate::Result; use crate::services; fn gen_random_bytes() -> Vec { @@ -452,4 +468,22 @@ mod tests { chain_same.copy_to_bytes(chain_same.remaining()) ); } + + #[tokio::test] + async fn test_debug() -> Result<()> { + let op = Operator::new(services::Memory::default()).unwrap().finish(); + let path = "test_file"; + + let mut writer = op.writer_with(path).chunk(8).await?; + let output = format!("{writer:?}"); + writer.abort().await?; + + assert!(output.contains("Writer"), "{output}"); + assert!(output.contains("memory"), "{output}"); + assert!(output.contains(path), "{output}"); + assert!(output.contains("args"), "{output}"); + assert!(output.contains("options"), "{output}"); + + Ok(()) + } }