Is there a way to run a closure on RwLock drop? - rust

I have a program that hides mutable state behind a RwLock. What I'd like to do is that when it's borrowed mutably (RW_LOCK.write()), on drop it should do something (namely, try to write to file, clean up the data behind the rwlock, etc.)
For example:
let DATA: RwLock<Data> = RwLock::new(Data { content: Default::default() } );
fn do_something() {
let mut state = DATA.write().unwrap();
state.change(5);
// ...
// Here, just before `state` goes out of scope (where it gets dropped and `RwLock` will allow
// other threads read/write access to `Data`, I would like for `RwLock` to auto-run `state.cleanup()`.
}
Is there a way to do this, or do I have to reimplement RwLock?

You can do this with a wrapper type:
Playground
use std::ops::{Deref, DerefMut, Drop};
use std::sync::{RwLock, RwLockWriteGuard};
type CleanupClosure<'a> = Fn(&mut RwLockWriteGuard<'a, Data>);
struct Data {
content: String,
}
impl Data {
fn change(&mut self, num: i32) {
println!("Changed to {}", num);
self.content = num.to_string();
}
}
struct RwLockWriteWrapper<'a, F: CleanupClosure<'a>>(RwLockWriteGuard<'a, Data>, F);
impl<'a, F: CleanupClosure<'a>> Deref for RwLockWriteWrapper<'a, F> {
type Target = RwLockWriteGuard<'a, Data>;
fn deref(&self) -> &RwLockWriteGuard<'a, Data> {
&self.0
}
}
impl<'a, F: CleanupClosure<'a>> DerefMut for RwLockWriteWrapper<'a, F> {
fn deref_mut(&mut self) -> &mut RwLockWriteGuard<'a, Data> {
&mut self.0
}
}
impl<'a, F: CleanupClosure<'a>> Drop for RwLockWriteWrapper<'a, F> {
fn drop(&mut self) {
println!("Cleaning up!");
self.1(&mut self.0)
}
}
fn main() {
let data: RwLock<Data> = RwLock::new(Data {
content: "Start".to_owned(),
});
do_something(&data);
do_something(&data);
}
fn do_something(data: &RwLock<Data>) {
// Write your own cleanup logic here
let mut state = RwLockWriteWrapper(data.write().unwrap(), |state| {
state.content = "Cleaned up".to_owned()
});
println!("do_something start: {}", state.content);
state.change(5);
println!("do_something after change: {}", state.content);
} // Automatically run cleanup here
It does require you to remember to wrap the type when you call .write() on it. You can wrap RwLock itself in another type that would return RwLockWriteWrapper to automate that as well.
This does become quite verbose, so I found a crate that impls the deref trait for you.
I am still not sure what closures you mentioned in the title meant.

You can create a wrapper that implements Drop:
struct CleanOnDrop<D, F>
where
F: FnOnce(&mut D),
{
data: D,
cleanup: Option<F>,
}
impl<D, F> CleanOnDrop<D, F>
where
F: FnOnce(&mut D),
{
pub fn new(data: D, cleanup: F) -> Self {
Self { data, cleanup: Some(cleanup) }
}
}
impl<D, F> Drop for CleanOnDrop<D, F>
where
F: FnOnce(&mut D)
{
fn drop(&mut self) {
if let Some(mut cleanup) = self.cleanup.take() {
cleanup(&mut self.data);
}
}
}
For convenience, you may want to implement Deref and DerefMut too, so that you can call methods on it directly:
use std::ops::{Deref, DerefMut};
impl<D, F> Deref for CleanOnDrop<D, F>
where
F: FnOnce(&mut D),
{
type Target = D;
fn deref(&self) -> &D {
&self.data
}
}
impl<D, F> DerefMut for CleanOnDrop<D, F>
where
F: FnOnce(&mut D),
{
fn deref_mut(&mut self) -> &mut D {
&mut self.data
}
}
Use the wrapper like this:
let data = RwLock::new(CleanOnDrop::new(
Data {
content: Default::default(),
},
|state| {
state.cleanup();
},
));

Related

Generic that could be object of type or reference of type

Given a struct and trait:
// Minimal version of the actual data structure and trait
trait MyTrait {
fn blub(&mut self);
}
struct MyStruct;
impl MyTrait for MyStruct {
fn blub(&mut self) {
println!("Blub!");
}
}
I would like to create a struct that can hold an object that implements MyTrait:
impl<T> Foo<T>
where
T: MyTrait,
{
fn new(t: T) -> Self {
Self { t }
}
fn run(&mut self) {
// Execute `blub` of `t`.
// Something like:
self.t.blub();
}
}
So far, that's easy. Now comes the crux: I want to accept both owned and mutably referenced types, like this:
fn main() {
let t0 = MyStruct;
let mut f0 = Foo::new(t0);
f0.run();
let mut t1 = MyStruct;
let mut f1 = Foo::new(&mut t1);
f1.run();
}
The code here of course doesn't work, because &mut MyStruct does not implement MyTrait.
In theory, this should be possible though, because MyTrait::blub takes &mut self, which is compatible with both owned and mutably borrowed types.
This is how far I've come. It works, but has two problems:
It has a pointless second generic
It requires PhantomData
use std::{borrow::BorrowMut, marker::PhantomData};
// Minimal version of the actual data structure and trait
trait MyTrait {
fn blub(&mut self);
}
struct MyStruct;
impl MyTrait for MyStruct {
fn blub(&mut self) {
println!("Blub!");
}
}
// Object that shall carry objects OR mutable references of type `MyTrait`
struct Foo<T, U> {
t: T,
_p: PhantomData<U>,
}
impl<T, U> Foo<T, U>
where
T: BorrowMut<U>,
U: MyTrait,
{
fn new(t: T) -> Self {
Self { t, _p: PhantomData }
}
fn run(&mut self) {
self.t.borrow_mut().blub();
}
}
fn main() {
let t0 = MyStruct;
let mut f0 = Foo::new(t0);
f0.run();
let mut t1 = MyStruct;
let mut f1: Foo<_, MyStruct> = Foo::new(&mut t1);
f1.run();
}
Blub!
Blub!
Is there a way to implement this more elegantly?
The only other elegant-ish way I have seen so far is to impl MyTrait for &mut MyStruct. Sadly, I do not own the trait or type, so I cannot do that. Although please tell me if my attempts here are misguided and this entire thing is an XY problem; and the actual thing I should do is to report this problem in said library so they can add that impl.
The simplest way is probably to add another implantation of MyTrait for &mut MyStruct.
impl MyTrait for &mut MyStruct {
fn blub(&mut self) {
println!("Blub!");
}
}
If you dont have access to the struct or trait, you can use an enum to manage the Owned and Borrowed versions and implement Deref/DerefMut to keep the usage of t the same.
enum Container<'a, T> {
Owned(T),
Borrowed(&'a mut T)
}
impl<'a, T: MyTrait> From<T> for Container<'a, T> {
fn from(t: T) -> Self {
Self::Owned(t)
}
}
impl<'a, T: MyTrait> From<&'a mut T> for Container<'a, T> {
fn from(t: &'a mut T) -> Self {
Self::Borrowed(t)
}
}
impl<'a, T> Deref for Container<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
match self {
Self::Owned(o) => o,
Self::Borrowed(o) => o
}
}
}
impl<'a, T> DerefMut for Container<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
match self {
Self::Owned(o) => o,
Self::Borrowed(o) => o
}
}
}
struct Foo<'a, T> {
t: Container<'a, T>
}
impl<'a, T> Foo<'a, T>
where
T: MyTrait,
{
fn new(t: impl Into<Container<'a, T>>) -> Self {
Self{ t: t.into() }
}
fn run(&mut self) {
self.t.blub();
}
}
Other solutions I found:
This one doesn't require looking at an enum at runtime, it solves types at compile time:
use std::marker::PhantomData;
// Minimal version of the actual data structure and trait
trait MyTrait {
fn blub(&mut self);
}
struct MyStruct;
impl MyTrait for MyStruct {
fn blub(&mut self) {
println!("Blub!");
}
}
trait MyTraitFrom<'a, T> {
fn mytrait_from(value: &'a mut T) -> Self;
}
impl<'a, T: MyTrait> MyTraitFrom<'a, T> for &'a mut T {
fn mytrait_from(value: &'a mut T) -> Self {
value
}
}
impl<'a, T: MyTrait> MyTraitFrom<'a, &'a mut T> for &'a mut T {
fn mytrait_from(value: &'a mut &'a mut T) -> Self {
let value: &'a mut T = value;
value
}
}
struct Foo<T, U> {
t: T,
_p: PhantomData<U>,
}
impl<'a, T: 'a, U: 'a> Foo<T, U>
where
&'a mut U: MyTraitFrom<'a, T>,
U: MyTrait,
{
fn new(t: T) -> Self {
Self { t, _p: PhantomData }
}
fn run(&'a mut self) {
let u: &'a mut U = MyTraitFrom::mytrait_from(&mut self.t);
u.blub();
}
}
fn main() {
let t0 = MyStruct;
let mut f0 = Foo::new(t0);
f0.run();
let mut t1 = MyStruct;
let mut f1 = Foo::new(&mut t1);
f1.run();
}
Blub!
Blub!

Trouble with stricter lifetime requirements when implementing FromIterator for LazyList

I was playing with the code from this answer but the FromIterator impl does not compile any more:
error[E0276]: impl has stricter requirements than trait --> src/lib.rs:184:9
| 184 | fn from_iter<I: IntoIterator<Item = T> + 'a>(itrbl: I) -> LazyList<'a, T> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `I: 'a`
For more information about this error, try `rustc --explain E0276`.
The slightly updated code is on the playground.
// only necessary because Box<FnOnce() -> R> doesn't work...
mod thunk {
pub trait Invoke<R = ()> {
fn invoke(self: Box<Self>) -> R;
}
impl<R, F: FnOnce() -> R> Invoke<R> for F {
#[inline(always)]
fn invoke(self: Box<F>) -> R { (*self)() }
}
}
// Lazy is lazily evaluated contained value using the above Invoke trait
// instead of the desire Box<FnOnce() -> T> or a stable FnBox (currently not)...
pub mod lazy {
use crate::thunk::Invoke;
use std::cell::UnsafeCell;
use std::mem::replace;
use std::ops::Deref;
// Lazy is lazily evaluated contained value using the above Invoke trait
// instead of the desire Box<FnOnce() -> T> or a stable FnBox (currently not)...
pub struct Lazy<'a, T: 'a>(UnsafeCell<LazyState<'a, T>>);
enum LazyState<'a, T: 'a> {
Unevaluated(Box<dyn Invoke<T> + 'a>),
EvaluationInProgress,
Evaluated(T),
}
use self::LazyState::*;
impl<'a, T: 'a> Lazy<'a, T> {
#[inline]
pub fn new<F: 'a + FnOnce() -> T>(func: F) -> Lazy<'a, T> {
Lazy(UnsafeCell::new(Unevaluated(Box::new(func))))
}
#[inline]
pub fn evaluated(val: T) -> Lazy<'a, T> {
Lazy(UnsafeCell::new(Evaluated(val)))
}
#[inline(always)]
fn force(&self) {
unsafe {
match *self.0.get() {
Evaluated(_) => {}, // nothing required; already Evaluated
EvaluationInProgress => panic!("Lazy::force called recursively!!!"),
_ => {
let ue = replace(&mut *self.0.get(), EvaluationInProgress);
if let Unevaluated(thnk) = ue {
*self.0.get() = Evaluated(thnk.invoke());
} // no other possiblity!
}
}
}
}
#[inline]
pub fn unwrap<'b>(self) -> T where T: 'b { // consumes the object to produce the value
self.force(); // evaluatate if not evealutated
match { self.0.into_inner() } {
Evaluated(v) => v,
_ => unreachable!() // previous code guarantees never not Evaluated
}
}
}
impl<'a, T: 'a> Deref for Lazy<'a, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
self.force(); // evaluatate if not evalutated
match *unsafe { &*self.0.get() } {
Evaluated(ref v) => v,
_ => unreachable!(),
}
}
}
}
// LazyList is an immutable lazily-evaluated persistent (memoized) singly-linked list
// similar to lists in Haskell, although here only tails are lazy...
// depends on the contained type being Clone so that the LazyList can be
// extracted from the reference-counted Rc heap objects in which embedded.
pub mod lazylist {
use crate::lazy::Lazy;
use std::rc::Rc;
use std::iter::FromIterator;
use std::mem::{replace, swap};
#[derive(Clone)]
pub enum LazyList<'a, T: 'a + Clone> {
Empty,
Cons(T, RcLazyListNode<'a, T>),
}
pub use self::LazyList::Empty;
use self::LazyList::Cons;
type RcLazyListNode<'a, T> = Rc<Lazy<'a, LazyList<'a, T>>>;
// impl<'a, T:'a> !Sync for LazyList<'a, T> {}
impl<'a, T: 'a + Clone> LazyList<'a, T> {
#[inline]
pub fn singleton(v: T) -> LazyList<'a, T> {
Cons(v, Rc::new(Lazy::evaluated(Empty)))
}
#[inline]
pub fn cons<F>(v: T, cntf: F) -> LazyList<'a, T>
where F: 'a + FnOnce() -> LazyList<'a, T>
{
Cons(v, Rc::new(Lazy::new(cntf)))
}
#[inline]
pub fn head(&self) -> &T {
if let Cons(ref hd, _) = *self {
return hd;
}
panic!("LazyList::head called on an Empty LazyList!!!")
}
#[inline]
pub fn tail<'b>(&'b self) -> &'b Lazy<'a, LazyList<'a, T>> {
if let Cons(_, ref rlln) = *self {
return &*rlln;
}
panic!("LazyList::tail called on an Empty LazyList!!!")
}
#[inline]
pub fn unwrap(self) -> (T, RcLazyListNode<'a, T>) {
// consumes the object
if let Cons(hd, rlln) = self {
return (hd, rlln);
}
panic!("LazyList::unwrap called on an Empty LazyList!!!")
}
#[inline]
fn iter(&self) -> Iter<'a, T> {
Iter(self)
}
}
impl<'a, T: 'a + Clone> Iterator for LazyList<'a, T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
match replace(self, Empty) {
Cons(hd, rlln) => {
let mut newll = (*rlln).clone();
swap(self, &mut newll); // self now contains tail, newll contains the Empty
Some(hd)
}
_ => None,
}
}
}
pub struct Iter<'a, T: 'a + Clone>(*const LazyList<'a, T>);
impl<'a, T: 'a + Clone> Iterator for Iter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
unsafe {
if let LazyList::Cons(ref v, ref r) = *self.0 {
self.0 = &***r;
Some(v)
} else {
None
}
}
}
}
impl<'i, 'l, T: 'i + Clone> IntoIterator for &'l LazyList<'i, T> {
type Item = &'i T;
type IntoIter = Iter<'i, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, T: 'a + Clone, > FromIterator<T> for LazyList<'a, T> {
fn from_iter<I: IntoIterator<Item = T> + 'a>(itrbl: I) -> LazyList<'a, T> {
let itr = itrbl.into_iter();
#[inline(always)]
fn next_iter<'b, R, Itr>(mut iter: Itr) -> LazyList<'b, R>
where R: 'b + Clone,
Itr: 'b + Iterator<Item = R>
{
match iter.next() {
Some(val) => LazyList::cons(val, move || next_iter(iter)),
None => Empty,
}
}
next_iter(itr)
}
}
}
Unfortunately I've exhausted ideas on how to try and fix this.
The code in the question (though not in the referenced answer, which has since been updated) relies on a soundness bug in older versions of the compiler (#18937) which has since been fixed.
It is not possible to implement FromIterator for LazyList, or indeed for any data structure, by storing the iterator inside the structure. This is because the FromIterator trait allows the implementor (Self) to outlive the iterator type (I::IntoIter). That the compiler ever accepted it was an oversight.
When copying code from the internet, be conscious of the age of the source. This code is also out of date in several other respects, notably:
it uses Rust 2015-style paths
it omits dyn on trait object types
the Invoke workaround is no longer needed, since dyn FnOnce() -> T works properly now.

How to implement Display on a trait object where the types already implement Display

I have some code which returns a trait object of type MyTrait so that it can return one of several different structs. I would like to implement the Display trait for the trait object so that I can print the object, with the details delegated to the various structs as they each need their own custom formatters.
I can achieve this by including a formatting method as part of the MyTrait definition, and then implementing Display for MyTrait and delegating - like this:
trait MyTrait {
fn is_even(&self) -> bool;
fn my_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result;
}
impl fmt::Display for MyTrait {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.my_fmt(f)
}
}
However, I already have the Display trait implemented for each of the structs which implement MyTrait. This means I end up with two methods for each struct which do the same thing - the fmt() method to satisfy the Display trait directly on the struct, and the my_fmt() method which is called by the code above. This seems clumsy and repetitive. Is there a simpler way to do it?
Here's a complete example program which illustrates the point. It's a little longer than I would have liked (it's based on the answer to my previous question Calling functions which return different types with shared trait and pass to other functions), but I couldn't think of a simpler way to illustrate the point. Of course, in this toy example the structs and the fmt functions are very simple; in my real application they are more complex.
use std::fmt;
trait MyTrait {
fn is_even(&self) -> bool;
fn my_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result;
}
struct First {
v: u8,
}
struct Second {
v: Vec<u8>,
}
impl MyTrait for First {
fn is_even(&self) -> bool {
self.v % 2 == 0
}
fn my_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.v)
}
}
impl MyTrait for Second {
fn is_even(&self) -> bool {
self.v[0] % 2 == 0
}
fn my_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.v[0])
}
}
fn make1() -> First {
First { v: 5 }
}
fn make2() -> Second {
Second { v: vec![2, 3, 5] }
}
// Implement Display for the structs and for MyTrait
impl fmt::Display for First {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.v)
}
}
impl fmt::Display for Second {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.v[0])
}
}
impl fmt::Display for MyTrait {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.my_fmt(f)
}
}
fn requires_mytrait<T: MyTrait + ?Sized>(v: &&T) {
println!("{:?}", v.is_even());
}
fn main() {
for i in 0..2 {
let v1;
let v2;
let v = match i {
0 => {
v1 = make1();
println!("> {}", v1); // Demonstrate that Display
// is implemented directly
// on the type.
&v1 as &MyTrait
}
_ => {
v2 = make2();
println!("> {}", v2); // Demonstrate that Display
// is implemented directly
// on the type.
&v2 as &MyTrait
}
};
requires_mytrait(&v);
println!("{}", v); // Here I print the trait object
}
}
Can anyone suggest a simpler, cleaner way to do this?
You can make Display a supertrait of MyTrait.
trait MyTrait: fmt::Display {
fn is_even(&self) -> bool;
}
This will make trait objects of MyTrait be Display. This only works if you expect all implementors of MyTrait to implement Display, but that was also the case in your previous solution.

Strange behavior of HRTBs

I have this code:
use std::fmt::Debug;
struct S<A>
where
for<'a> A: Debug + 'a,
{
f: Box<Fn(A) -> i32>,
}
impl<A> S<A>
where
for<'a> A: Debug + 'a,
{
fn call(&self, a: A) {
println!("Return {:?}", (self.f)(a));
}
}
fn create<A>(f: Box<Fn(A) -> i32>) -> S<A>
where
for<'a> A: Debug + 'a,
{
S::<A> { f }
}
fn helper() {
let x = create::<&i32>(Box::new(|x: &i32| *x * 2));
let arg = 333;
x.call(&arg);
}
fn main() {
let x = helper();
}
It's failed to compile:
error[E0310]: the parameter type `A` may not live long enough
In code 2, I changed Fn(A) -> i32 to Fn(&A) -> i32, the code works.
...
f: Box<Fn(&A) -> i32>,
...
Since A is argument of Fn trait, it's a type that has Higher-Rank lifetime. It shouldn't be affected by the lifetime of struct S<A> .
But why can't code 1 be compiled?
How can I workaround it for borrow or non-borrow type A?
There is no easy way to make helper work in current Rust, even if you remove all the for<'a> A: Debug + 'a, bounds (which only further restricts what types A can be, whereas you want to allow more).
This is as simple as I can make your example:
struct S<A> {
f: Box<Fn(A) -> i32>,
}
impl<A> S<A> {
fn call(&self, a: A) {
println!("Return {:?}", (self.f)(a));
}
}
fn create<A>(f: Box<Fn(A) -> i32>) -> S<A> {
S { f }
}
fn helper() {
let x = create(Box::new(|x: &i32| *x * 2));
let arg = 333;
x.call(&arg);
}
fn main() {
helper();
}
The reason it doesn't work is that A "comes from the outside", and Rust can't infer that you want for<'a> S<&'a A>, it can't even talk about such a type.
Note that if let arg = 333; is placed above let x, this example does compile (because it infers a reference to arg specifically, not a for<'a>).
The closest you can get today is with an associated type on a trait with a lifetime parameter, e.g.:
// Emulating `type Type<'a>` by moving `'a` to the trait.
trait Apply<'a> {
type Type;
}
struct Plain<T>(std::marker::PhantomData<T>);
impl<'a, T> Apply<'a> for Plain<T> {
type Type = T;
}
struct Ref<T: ?Sized>(std::marker::PhantomData<T>);
impl<'a, T: ?Sized + 'a> Apply<'a> for Ref<T> {
type Type = &'a T;
}
struct S<A: for<'a> Apply<'a>> {
f: Box<for<'a> Fn(<A as Apply<'a>>::Type) -> i32>,
}
impl<A: for<'a> Apply<'a>> S<A> {
fn call<'a>(&self, a: <A as Apply<'a>>::Type) {
println!("Return {:?}", (self.f)(a));
}
}
fn create<A: for<'a> Apply<'a>>(
f: Box<for<'a> Fn(<A as Apply<'a>>::Type) -> i32>,
) -> S<A> {
S { f }
}
fn helper() {
let x = create::<Ref<i32>>(Box::new(|x: &i32| *x * 2));
let arg = 333;
x.call(&arg);
}
fn main() {
helper();
}
However, it turns out that this encoding hits https://github.com/rust-lang/rust/issues/52812, so it's not actually usable at the moment (and I'm not aware of an workaround).

How do I provide a default Debug implementation?

It is considered good practice to #[derive(Debug)] for most structs you create to aid in debugging. However, this is not possible if your struct contains a type without Debug, such as traits. But if the trait is under my control, is there something I can do to let users' implementations of said trait show up in the debug message?
I could require that people who implement my trait also implement Debug, but I don't like having to add that arbitrary requirement:
trait MyTrait: Debug { ... }
I could just implement Debug for my trait:
trait MyTrait { ... }
impl Debug for MyTrait {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "MyTrait {{ ... }}")
}
}
This doesn't allow implementations to override Debug - it's almost as if the function is not virtual. How can I make this work?
use std::fmt;
use std::fmt::{ Formatter, Debug };
#[derive(Debug)]
struct A {
a: Box<Data>,
}
trait Data {}
impl Debug for Data {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "Data{{ ... }}")
}
}
#[derive(Debug)]
struct B(i32);
impl Data for B {}
fn main() {
let a = A{ a: Box::new(B(42)) };
println!("{:?}", a);
}
Outputs:
A { a: Data{ ... } }
What I want:
A { a: B(42) }
I only want the first output when B does not implement Debug.
You can create your own trait method. Types that wish to have enhanced debugging and implement Debug can delegate:
use std::fmt;
use std::fmt::{ Formatter, Debug };
#[derive(Debug)]
struct Container(Box<Data>);
trait Data {
fn debug_fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "Data {{ ... }}")
}
}
impl Debug for Data {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
self.debug_fmt(f)
}
}
#[derive(Debug)]
struct Overrides(i32);
impl Data for Overrides {
fn debug_fmt(&self, f: &mut Formatter) -> fmt::Result {
self.fmt(f)
}
}
#[derive(Debug)]
struct Defaults(i32);
impl Data for Defaults {}
fn main() {
let a = Container(Box::new(Overrides(42)));
println!("{:?}", a);
let a = Container(Box::new(Defaults(42)));
println!("{:?}", a);
}
An alternate solution that requires the unstable specialization feature:
#![feature(specialization)]
use std::fmt;
use std::fmt::{Formatter, Debug};
struct Container<D>(Box<D>) where D: Data;
impl<D> Debug for Container<D>
where D: Data
{
default fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "Container(Data {{ ... }})")
}
}
impl<D> Debug for Container<D>
where D: Data + Debug
{
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "Container({:?})", self.0)
}
}
trait Data {}
#[derive(Debug)]
struct Overrides(i32);
impl Data for Overrides {}
struct Defaults(i32);
impl Data for Defaults {}
fn main() {
let a = Container(Box::new(Overrides(42)));
println!("{:?}", a);
let a = Container(Box::new(Defaults(42)));
println!("{:?}", a);
}
Note that this places the burden on the container.

Resources