yui_core/util/
format.rs

1use std::fmt::Display;
2use itertools::Itertools;
3use num_traits::ToPrimitive;
4use crate::IntoDigits;
5
6pub fn paren_expr<S>(s: S) -> String
7where S: Display {
8    let s = s.to_string();
9    if s.contains(' ') { 
10        format!("({s})")
11    } else { 
12        s
13    }
14}
15
16pub fn lc<X, R, S>(mut terms: S) -> String
17where 
18    X: Display, 
19    R: Display, 
20    S: Iterator<Item = (X, R)>
21{ 
22    let mut res: Vec<String> = vec![];
23    
24    if let Some((x, r)) = terms.next() {
25        let r = paren_expr(r);
26        let x = x.to_string();
27
28        let term = if r == "1" { 
29            x
30        } else if r == "-1" { 
31            format!("-{x}")
32        } else if x == "1" {
33            format!("{r}")
34        } else { 
35            format!("{r}{x}")
36        };
37
38        res.push(term)
39    };
40
41    for (x, r) in terms {
42        let r = paren_expr(r);
43        let x = x.to_string();
44
45        let (op, r) = if let Some(r) = r.strip_prefix('-') { 
46            ("-", r.to_owned()) 
47        } else { 
48            ("+", r.to_owned())
49        };
50
51        let term = if r == "1" { 
52            x
53        } else if x == "1" { 
54            r.to_string()
55        } else { 
56            format!("{r}{x}")
57        };
58
59        res.push(op.to_string());
60        res.push(term);
61    }
62
63    if res.is_empty() { 
64        "0".to_string()
65    } else {
66        res.join(" ")
67    }
68}
69
70pub fn subscript<I>(i: I) -> String
71where I: ToPrimitive {
72    let i = i.to_isize().unwrap();
73
74    if i == 0 { 
75        return '\u{2080}'.into()
76    }
77
78    let (init, i) = if i > 0 { 
79        (String::new(), i as usize)
80    } else { 
81        ('\u{208B}'.into(), -i as usize)
82    };
83
84    i.into_digits().into_iter().fold(init, |mut res, d| {
85        let c = char::from_u32( ('\u{2080}' as u32) + (d as u32) ).unwrap();
86        res.push(c);
87        res
88    })
89}
90
91pub fn superscript<I>(i: I) -> String 
92where I: ToPrimitive {
93    let i = i.to_isize().unwrap();
94
95    if i == 0 { 
96        return '\u{2070}'.into()
97    }
98
99    let (init, i) = if i > 0 { 
100        (String::new(), i as usize)
101    } else { 
102        ('\u{207B}'.into(), -i as usize)
103    };
104
105    i.into_digits().into_iter().fold(init, |mut res, d| {
106        let c = match d { 
107            1 => '\u{00B9}',
108            2 => '\u{00B2}',
109            3 => '\u{00B3}',
110            _ => char::from_u32(('\u{2070}' as u32) + (d as u32)).unwrap()
111        };
112        res.push(c);
113        res
114    })
115}
116
117pub fn table<S, I, J, I1, I2, D, F>(head: S, rows: I1, cols: I2, entry: F) -> String
118where 
119    S: Display,
120    I: Display,
121    J: Display,
122    I1: Iterator<Item = I>,
123    I2: Iterator<Item = J>,
124    D: Display,
125    F: Fn(&I, &J) -> D
126{
127    use prettytable::*;
128
129    let rows = rows.collect_vec();
130    let cols = cols.collect_vec();
131
132    fn row<I>(head: String, cols: I) -> Row
133    where I: Iterator<Item = String> { 
134        let mut cells = vec![Cell::new(head.as_str())];
135        cells.extend(cols.map(|str| Cell::new(str.as_str())));
136        Row::new(cells)
137    }
138
139    let mut table = Table::new();
140
141    table.set_format(*format::consts::FORMAT_CLEAN);
142    table.set_titles(row(
143        head.to_string(),
144        cols.iter().map(|j| j.to_string() )
145    ));
146
147    for i in rows.iter() { 
148        table.add_row(row(
149            i.to_string(),
150            cols.iter().map(|j| format!("{}", entry(i, j)))
151        ));
152    }
153
154    table.to_string()
155}
156
157#[cfg(test)]
158mod tests {
159    use super::*;
160
161    #[test]
162    fn test_subscript() { 
163        assert_eq!(subscript(0), "₀");
164        assert_eq!(subscript(1234567890), "₁₂₃₄₅₆₇₈₉₀");
165        assert_eq!(subscript(-1234567890), "₋₁₂₃₄₅₆₇₈₉₀");
166    }
167
168    #[test]
169    fn test_superscript() { 
170        assert_eq!(superscript(0), "⁰");
171        assert_eq!(superscript(1234567890), "¹²³⁴⁵⁶⁷⁸⁹⁰");
172        assert_eq!(superscript(-1234567890), "⁻¹²³⁴⁵⁶⁷⁸⁹⁰");
173    }
174
175    #[test]
176    fn test_table() { 
177        let table = table("", 1..=3, 4..=6, |i, j| i * 10 + j);
178        let a = "    4   5   6 \n 1  14  15  16 \n 2  24  25  26 \n 3  34  35  36 \n";
179        assert_eq!(table, a.to_string());
180    }
181}