use std::fmt::{self, Debug, Formatter, Write};
pub(crate) struct FmtLimit<'a, T> {
limit: usize,
item: &'a T,
}
impl<'a, T> FmtLimit<'a, T> {
#[inline]
pub(crate) fn new(limit: usize, item: &'a T) -> Self {
FmtLimit { limit, item }
}
}
struct LimitWriter<'a, W> {
inner: &'a mut W,
left: usize,
closed: bool,
}
impl<'a, W> LimitWriter<'a, W> {
#[inline]
fn new(inner: &'a mut W, limit: usize) -> Self {
LimitWriter {
inner,
left: limit,
closed: false,
}
}
}
impl<W> Write for LimitWriter<'_, W>
where
W: Write,
{
#[inline]
fn write_str(&mut self, s: &str) -> fmt::Result {
if self.closed {
return Ok(());
}
if self.left == 0 {
self.closed = true;
self.inner.write_str("...")?;
return Ok(());
}
for c in s.chars().take(self.left) {
self.write_char(c)?;
}
Ok(())
}
#[inline]
fn write_char(&mut self, c: char) -> fmt::Result {
if self.closed {
return Ok(());
}
if self.left == 0 {
self.closed = true;
self.inner.write_str("...")?;
return Ok(());
}
self.left -= 1;
self.inner.write_char(c)
}
}
impl<T> Debug for FmtLimit<'_, T>
where
T: Debug,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let mut limit_writer = LimitWriter::new(f, self.limit);
write!(&mut limit_writer, "{:?}", self.item)
}
}
#[cfg(test)]
mod tests {
use crate::utils::fmt_limit::FmtLimit;
#[test]
fn limit_debug_works() {
let collection: Vec<_> = (0..5).collect();
assert_eq!(format!("{:?}", collection), "[0, 1, 2, 3, 4]");
assert_eq!(format!("{:?}", FmtLimit::new(3, &collection)), "[0,...");
assert_eq!(format!("{:?}", FmtLimit::new(0, &collection)), "...");
assert_eq!(
format!("{:?}", FmtLimit::new(1000, &collection)),
"[0, 1, 2, 3, 4]"
);
assert_eq!(
format!("{:?}", FmtLimit::new(15, &collection)),
"[0, 1, 2, 3, 4]"
);
}
}