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(()) + } }