As @user4815162342 commented, using specialization, this is possible.
I'll provide a slightly different approach from what they specified in their comment, to keep the same if ... { ... }
setup that you had in your original code.
The idea is to have a trait AsMaybeDebug
with an associated type Debug
, which always implements Debug
and a function to go from &Self
to Option<&Self::Debug>
:
trait AsMaybeDebug {
type Debug: Debug;
fn as_maybe_debug(&self) -> Option<&Self::Debug>;
}
After this we make a default impl for all T
, with the debug type being !
, the never type, and always return None
.
impl<T> AsMaybeDebug for T {
default type Debug = !;
default fn as_maybe_debug(&self) -> Option<&Self::Debug> {
None
}
}
Instead of the never type, you could choose any type that always implemented Debug
but still returning None
.
Afterwards we specialize for T: Debug
by returning Self
:
impl<T: Debug> AsMaybeDebug for T {
type Debug = Self;
fn as_maybe_debug(&self) -> Option<&Self::Debug> {
Some(self)
}
}
Finally in test
we just call as_maybe_debug
and check if T: Debug
fn test<T: Eq>(a: T, b: T){
if a != b {
println!("Not equal!");
if let (Some(a), Some(b)) = (a.as_maybe_debug(), b.as_maybe_debug()) {
println!("{:?} != {:?}", a, b);
}
}
}
You can check in the playground both that it works and that the assembly generated for test_non_debug
doesn't have any debugging calls, only the single call to std::io::_print
.
It unfortunately isn't possible to retrieve the original a
or b
inside the if
after calling as_maybe_debug
.
This is due to <Self as AsMaybeDebug>::Debug
not being
convertible back to Self
.
This can be fixed, but not easily as it requires updates from the standard library.
Requiring AsMaybeDebug::Debug: AsRef<Self>
doesn't work for 2 reasons:
-
- There is no
impl<T> AsRef<T> for T
yet, this is due to specialization still being incomplete, I assume.
-
- There is no
impl<T> AsRef<T> for !
yet. Not sure if this impl can be made even with specialization or not, but it would be required.
Also, although the specialization
can be unsound, I believe that the trait and it's impls cannot be used for unsoundness, you would need a specific setup to be able to generate unsoundness from it, which this lacks.