You cannot do this without actually performing the formatting. Formatting is lazy by default and the formatting traits do not have a method that allows querying what the size would be.
Additionally, a type's implementation of Debug::fmt may or may not allocate, so it's impossible to say that no allocation will occur.
The simplest thing to do is create a string and return the length of the string:
fn width(to_print_later: &impl std::fmt::Debug) -> usize {
format!("{:?}", to_print_later).len()
}
If you want to avoid your own allocation, you can write your own implementer of fmt::Write and format into it, only counting the length:
use std::fmt::{self, Write};
fn width(to_print_later: &impl fmt::Debug) -> usize {
let mut c = CountingWriter::default();
write!(&mut c, "{:?}", to_print_later).expect("Exceeded the usize");
c.0
}
#[derive(Debug, Default)]
struct CountingWriter(usize);
impl fmt::Write for CountingWriter {
fn write_str(&mut self, s: &str) -> fmt::Result {
self.0 = usize::checked_add(self.0, s.len()).ok_or(fmt::Error)?;
Ok(())
}
}
This isn't a sure performance win, as it's possible that the implementation of Debug::fmt is the heavyweight part, not the allocation. As usual, profile to know what's best for your case.
Note that I use Debug in this answer, but it applies to the other traits like Display and LowerHex as well.