1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
use core::fmt;
use core::fmt::Write;

use crate::{new, Matrix, Vector};

#[derive(Debug, Default)]
struct CharCounter(usize);

impl fmt::Write for CharCounter {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        self.0 += s.chars().count();
        Ok(())
    }
}

macro_rules! count_chars {
    ($($arg:tt)*) => {{
        let mut counter = CharCounter::default();
        write!(counter, $($arg)*).unwrap();
        counter.0
    }};
}

fn fmt_matrix<T, F1, F2, const M: usize, const N: usize>(
    matrix: &Matrix<T, M, N>,
    f: &mut fmt::Formatter<'_>,
    width_fn: F1,
    mut fmt_fn: F2,
) -> fmt::Result
where
    F1: FnMut(&T) -> usize + Copy,
    F2: FnMut(&mut fmt::Formatter<'_>, &T, usize) -> fmt::Result + Copy,
{
    if M == 1 || N == 1 {
        f.write_str("(")?;
        for (i, d) in matrix.iter().enumerate() {
            if i != 0 {
                f.write_str(", ")?;
            }
            fmt_fn(f, d, 0)?
        }
        f.write_str(")")?;
    } else {
        let widths = matrix
            .iter_columns()
            .map(|col| col.iter().map(width_fn).max().unwrap_or(0));
        let widths: Vector<usize, N> = unsafe { new::collect_unchecked(widths) };

        for (i, row) in matrix.iter_rows().enumerate() {
            let (left, right) = match i {
                0 => ("⎛ ", " ⎞\n"),
                i if i != M - 1 => ("⎜ ", " ⎟\n"),
                _ => ("⎝ ", " ⎠"),
            };

            f.write_str(left)?;
            for (i, (d, width)) in row.iter().zip(widths).enumerate() {
                if i != 0 {
                    f.write_str(", ")?;
                }
                fmt_fn(f, d, width)?;
            }
            f.write_str(right)?;
        }
    }
    Ok(())
}

impl<T: fmt::Debug, const M: usize, const N: usize> fmt::Debug for Matrix<T, M, N> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let precision = f.precision();
        fmt_matrix(
            self,
            f,
            |d| match precision {
                Some(places) => count_chars!("{:.1$?}", d, places),
                None => count_chars!("{:?}", d),
            },
            |f, d, width| match precision {
                Some(places) => write!(f, "{:1$.2$?}", d, width, places),
                None => write!(f, "{:1$?}", d, width),
            },
        )
    }
}

impl<T: fmt::Display, const M: usize, const N: usize> fmt::Display for Matrix<T, M, N> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let precision = f.precision();
        fmt_matrix(
            self,
            f,
            |d| match precision {
                Some(places) => count_chars!("{:.1$}", d, places),
                None => count_chars!("{}", d),
            },
            |f, d, width| match precision {
                Some(places) => write!(f, "{:1$.2$}", d, width, places),
                None => write!(f, "{:1$}", d, width),
            },
        )
    }
}