use crate::Tensor;
use std::fmt;
#[cfg(feature = "dynamic")]
use crate::dynamic::Element;
#[cfg(feature = "dynamic")]
use crate::dynamic::storage::DynamicTensor;
const MAX_DISPLAY_COLUMNS: usize = 12;
const MAX_TENSOR_PREVIEW_VALUES: usize = 12;
impl fmt::Display for Tensor {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
#[cfg(feature = "dynamic")]
if let Some(dyn_t) = &self.dynamic {
return fmt_dynamic(dyn_t, f);
}
fmt_numeric(&self.data, &self.shape, f)
}
}
fn fmt_numeric(data: &[f64], shape: &[usize], f: &mut fmt::Formatter<'_>) -> fmt::Result {
if data.is_empty() {
return write!(f, "shape={shape:?} values={data:?}");
}
match shape {
[] => write!(f, "{:?}", data[0]),
[n] => f.write_str(&row(*n, f.alternate(), |i| format!("{:?}", data[i]))),
[rows, cols] => f.write_str(&grid(*rows, *cols, f.alternate(), |i| {
format!("{:?}", data[i])
})),
_ => write!(f, "shape={shape:?} values={data:?}"),
}
}
#[cfg(feature = "dynamic")]
fn dynamic_cell_text(e: &Element) -> String {
match e {
Element::Float(v) => format!("{v:?}"),
other => other.to_string(),
}
}
#[cfg(feature = "dynamic")]
fn fmt_dynamic(dyn_t: &DynamicTensor, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let shape = dyn_t.shape.as_slice();
if dyn_t.len == 0 {
return write!(f, "shape={shape:?} values=[]");
}
let cell = |i: usize| dyn_t.get_flat(i).map(dynamic_cell_text).unwrap_or_default();
match shape {
[] => f.write_str(&cell(0)),
[n] => f.write_str(&row(*n, f.alternate(), cell)),
[rows, cols] => f.write_str(&grid(*rows, *cols, f.alternate(), cell)),
_ => {
let values: Vec<String> = (0..dyn_t.len).map(cell).collect();
write!(f, "shape={shape:?} values=[{}]", values.join(", "))
}
}
}
fn row(n: usize, alternate: bool, cell: impl Fn(usize) -> String) -> String {
let shown = if alternate {
n
} else {
n.min(MAX_TENSOR_PREVIEW_VALUES)
};
let cells: Vec<String> = (0..shown).map(cell).collect();
let width = cells.iter().map(String::len).max().unwrap_or(0);
let line = cells
.iter()
.map(|c| format!("{c:>width$}"))
.collect::<Vec<_>>()
.join(" ");
if shown < n {
format!("{line}\n... {} more values", n - shown)
} else {
line
}
}
fn grid(rows: usize, cols: usize, alternate: bool, cell: impl Fn(usize) -> String) -> String {
let shown_cols = if alternate {
cols
} else {
cols.min(MAX_DISPLAY_COLUMNS)
};
let formatted: Vec<Vec<String>> = (0..rows)
.map(|r| (0..shown_cols).map(|c| cell(r * cols + c)).collect())
.collect();
let mut widths = vec![0usize; shown_cols];
for line in &formatted {
for (c, cell) in line.iter().enumerate() {
widths[c] = widths[c].max(cell.len());
}
}
let body = formatted
.iter()
.map(|line| {
line.iter()
.enumerate()
.map(|(c, cell)| format!("{cell:>w$}", w = widths[c]))
.collect::<Vec<_>>()
.join(" ")
})
.collect::<Vec<_>>()
.join("\n");
if shown_cols < cols {
format!("{body}\n... {} more columns", cols - shown_cols)
} else {
body
}
}
#[cfg(test)]
mod tests;