kosiew commented on code in PR #16926:
URL: https://github.com/apache/datafusion/pull/16926#discussion_r2233803439


##########
datafusion/execution/src/memory_pool/memory_report.rs:
##########
@@ -0,0 +1,118 @@
+use super::{human_readable_size, MemoryReservation};
+use crate::memory_pool::pool::{
+    FairSpillPool, GreedyMemoryPool, TrackConsumersPool, UnboundedMemoryPool,
+};
+use crate::memory_pool::MemoryPool;
+use datafusion_common::Result;
+use datafusion_expr::Accumulator;
+use std::any::Any;
+
+/// Helper trait to provide memory usage breakdowns for debugging.
+///
+/// Implemented for [`MemoryReservation`] and any [`Accumulator`] via a blanket
+/// implementation that relies on [`Accumulator::size`].
+///
+/// # Example
+/// ```
+/// # use std::sync::Arc;
+/// # use datafusion_execution::memory_pool::{ExplainMemory, GreedyMemoryPool, 
MemoryConsumer};
+/// let pool = Arc::new(GreedyMemoryPool::new(1024));
+/// let mut reservation = MemoryConsumer::new("example").register(&pool);
+/// reservation.try_grow(256).unwrap();
+/// println!("{}", reservation.explain_memory().unwrap());
+/// ```
+pub trait ExplainMemory {
+    /// Returns a human readable string describing memory usage.
+    fn explain_memory(&self) -> Result<String>;
+}
+
+impl ExplainMemory for MemoryReservation {
+    fn explain_memory(&self) -> Result<String> {
+        Ok(format!(
+            "{}#{} reserved {}",
+            self.consumer().name(),
+            self.consumer().id(),
+            human_readable_size(self.size())
+        ))
+    }
+}
+
+impl<T: Accumulator + ?Sized> ExplainMemory for T {

Review Comment:
   Hey @rluvaton! ๐Ÿ‘‹
   
   You're totally right to be cautious โ€” that blanket impl of ExplainMemory for 
T where T: Accumulator will indeed block any other downstream impls of 
ExplainMemory for overlapping traits like T: MyTrait, due to Rust's coherence 
and orphan rules.
   
   ๐Ÿ’ก Workaround: You can safely achieve what you want using a newtype pattern. 
That way, you avoid trait conflicts while still providing a blanket impl.
   
   Hereโ€™s a minimal example:
   
   ```rust
   // Newtype wrapper
   struct AccumExplainer<T: Accumulator>(T);
   
   // Blanket impl only applies to the wrapper, not all T
   impl<T: Accumulator> ExplainMemory for AccumExplainer<T> {
       fn explain(&self) -> String {
           format!("Memory usage: {}", self.0.accumulate())
       }
   }
   
   // Convenience (optional)
   impl<T: Accumulator> From<T> for AccumExplainer<T> {
       fn from(inner: T) -> Self {
           Self(inner)
       }
   }
   ```
   You can now wrap any Accumulator type like this:
   
   ```rust
   fn explain_it<T: Accumulator>(thing: T) {
       let wrapped = AccumExplainer::from(thing);
       println!("{}", wrapped.explain());
   }
   ```
   
   This gives you a clean, conflict-free path to implement ExplainMemory 
broadly without locking out other impls for T in the future.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscr...@datafusion.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: github-unsubscr...@datafusion.apache.org
For additional commands, e-mail: github-h...@datafusion.apache.org

Reply via email to