I'll sketch something out if you need me to
even if you don't need it, I did this anyways ![]()
/// Extends a (possibly unsized) value with a Debug string.
// (This type is unsized when T is unsized)
pub struct Debuggable<T: ?Sized> {
text: &'static str,
value: T,
}
/// Produce a Debuggable<T> from an expression for T
macro_rules! dbg {
($($body:tt)+) => {
Debuggable {
text: stringify!($($body)+),
value: $($body)+,
}
};
}
// Note: this type is unsized
pub type PolFn = Debuggable<Fn(Rc<Pol>) -> Rc<Pol>>;
impl<T: ?Sized> fmt::Debug for Debuggable<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
{ write!(f, "{}", self.text) }
}
// This makes Debuggable have most methods of the thing it wraps.
// It also lets you call it when T is a function.
impl<T: ?Sized> ::std::ops::Deref for Debuggable<T>
{
type Target = T;
fn deref(&self) -> &T { &self.value }
}
fn main() {
let d: &PolFn = &dbg!(|x| {
let _ = "random code so you can see how it's formatted";
assert_eq!(3 * (1 + 2), 9);
x
});
println!("{:?}", d);
}
Updated 1/09: @juggle-tux has pointed out these objects can actually be called using standard function-call syntax (I didn't realize Deref could do that!), so I removed the call method.
In Pol you would store Rc<PolFn>. In your code you will need to wrap dbg!() around a lot of your closures.
In the playground this prints:
| x | {
let _ = "random code so you can see how it's formatted" ; assert_eq ! (
3 * ( 1 + 2 ) , 9 ) ; x }
as you can see, the formatting is not spectacular, but that's because all the whitespace gets normalized away during tokenization. I don't think you can get much better without resorting to crazy hacks like preprocessing your code in a build script.