use super::{Owner, Row, Stamp};
pub(super) const ABSENT: &str = "-";
const HEADERS: [&str; 5] = ["SKILL", "OWNER", "STATE", "LAST USE", "LAST PATCH"];
impl Owner {
pub(super) fn label(&self) -> &'static str {
match self {
Owner::Pool => "pool",
Owner::Workspace => "workspace",
}
}
}
impl super::State {
pub(super) fn label(&self) -> &'static str {
match self {
super::State::Active => "active",
super::State::Claimed => "claimed",
super::State::Unused => "unused",
super::State::Archived => "archived",
}
}
}
pub(crate) fn render(rows: &[Row]) -> String {
let cells: Vec<[String; 5]> = rows
.iter()
.map(|r| {
[
r.name.clone(),
r.owner.label().to_owned(),
r.state.label().to_owned(),
age(r.last_use.as_ref()),
age(r.last_patch.as_ref()),
]
})
.collect();
let mut widths = HEADERS.map(str::len);
for row in &cells {
for (w, cell) in widths.iter_mut().zip(row) {
*w = (*w).max(cell.len());
}
}
let head = HEADERS.map(str::to_owned);
std::iter::once(&head)
.chain(cells.iter())
.map(|row| line(row, &widths))
.collect::<Vec<String>>()
.join("\n")
}
fn line(row: &[String; 5], widths: &[usize; 5]) -> String {
row.iter()
.zip(widths.iter().copied())
.map(|(cell, w)| format!("{cell:<w$}"))
.collect::<Vec<String>>()
.join(" ")
.trim_end()
.to_owned()
}
fn age(stamp: Option<&Stamp>) -> String {
stamp.map_or_else(|| ABSENT.to_owned(), |s| s.age.clone())
}