Is there a way to limit vector/string length for debug output in Rust?

Viewed 301

I need to print arbitrary structures in human-readable form. The problem is they may contain very large vectors, so I would like to limit their length up to N elements appended with ellipsis.

What is a simplest way to achieve that without messing around with procedural macros? Some crates that provide that out-of-the-box?

2 Answers

I'm not aware of any crate doing that, but you can easily create a newtype wrapper:

use std::fmt;

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct LimitedVec<T>(pub Vec<T>);
const LIMIT: usize = 5;
impl<T: fmt::Debug> fmt::Debug for LimitedVec<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_list().entries(self.0.iter().take(LIMIT)).finish()
    }
}

Playground.

Chayim Friedman's answer doesn't include adding the ellipsis. Tweaking the implementation of fmt::Debug further to support this is not too tricky. I did it by adjusting their code to wrap the iterated values into an enum with a More value. The code can probably be cleaned up a bit.

use core::fmt::Formatter;
use std::fmt;

enum OrMore<T> {
    Value(T),
    More,
}

impl<T: fmt::Debug> fmt::Debug for OrMore<T> {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
        match self {
            OrMore::Value(t) => fmt::Debug::fmt(t, f),
            OrMore::More => write!(f, "..."),
        }
    }
}

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct LimitedVec<T>(pub Vec<T>);
const LIMIT: usize = 5;
impl<T: fmt::Debug> fmt::Debug for LimitedVec<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if self.0.len() <= LIMIT {
            f.debug_list().entries(self.0.iter().take(LIMIT)).finish()
        } else {
            f.debug_list()
                .entries(
                    self.0
                        .iter()
                        .take(LIMIT)
                        .map(OrMore::Value)
                        .chain(vec![OrMore::More].into_iter()),
                )
                .finish()
        }
    }
}

fn main() {
    let w = LimitedVec(vec![1, 2, 3, 4, 5]);
    let v = LimitedVec(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
    println!("{:?}", w); // [1, 2, 3, 4, 5]
    println!("{:?}", v); // [1, 2, 3, 4, 5, ...]
}

The code might be shorter if we used an explicit loop using write!(f, ...), rather than using the f.debug_list() approach, but IIRC that doesn't play well with the multi-line debug format {:#?}.

Related