gooey-rs 0.12.1

Tile-based UI library with audio support
Documentation
//! Some utilities for making formatted table strings

pub macro make_table {
  ($([$($item:expr),+]),+$(, ($spacing:expr))?) => {
    mk_table (
      vec![],
      vec![$(box_vec!($($item),+)),+]
      $(,$spacing)?
    )
  }
}

pub macro box_vec {
  ($($item:expr),*) => {
    vec![$(Box::new ($item)),*]
  }
}

pub fn mk_table (
  headers : Vec <Vec <Box <dyn ToString>>>,
  rows    : Vec <Vec <Box <dyn ToString>>>,
  spacing : usize
) -> String {
  use std::fmt::Write;
  let mut cols = vec![];
  for row in headers.iter().chain (rows.iter()) {
    for (i, entry) in row.iter().enumerate() {
      if cols.get (i).is_none() {
        cols.push (vec![]);
      }
      let col = &mut cols[i];
      col.push (entry.to_string());
    }
  }
  let col_lens = cols.iter().map (|col| col.iter().map (String::len).max().unwrap_or (0))
    .collect::<Vec <_>>();
  let col_numeric = cols.iter().map (
      |col| col.iter().skip (headers.len()).all (|entry| entry.parse::<f32>().is_ok())
    ).collect::<Vec <_>>();
  let mut out = String::new();
  for (i, _) in headers.iter().chain (rows.iter()).enumerate() {
    for (j, col) in cols.iter().enumerate() {
      if let Some (entry) = col.get (i) {
        let col_width = col_lens[j];
        let col_num = if i < headers.len() {
          false
        }  else {
          col_numeric[j]
        };
        if col_num {
          let _ = write!(out, "{entry:>col_width$}");
        } else {
          let _ = write!(out, "{entry:col_width$}");
        }
        out.push_str (&" ".repeat (spacing));
      } else {
        break
      }
    }
    out.push ('\n');
  }
  out
}