s5/
display.rs

1use std::fmt;
2use std::fmt::{Error, Formatter};
3
4pub trait Printable {
5    fn to_print_units(&self) -> PrintUnits;
6}
7
8#[derive(Clone, Debug)]
9pub struct PrintUnits(Vec<PrintUnit>);
10
11impl PrintUnits {
12    pub fn new(units: Vec<PrintUnit>) -> PrintUnits {
13        PrintUnits(units)
14    }
15
16    /// Move `self` to the right of `others`.
17    pub fn right_of(&mut self, others: &PrintUnits) {
18        let offset = others.max_x() - self.min_x() + 1;
19        self.shift_right(offset);
20    }
21
22    /// Move `self` on top of `others`.
23    pub fn on_top_of(&mut self, others: &PrintUnits) {
24        let offset = self.max_y() - others.min_y() + 1;
25        self.shift_down(-offset);
26    }
27
28    /// Move `self` on below `others`.
29    pub fn below(&mut self, others: &PrintUnits) {
30        let offset = others.max_y() - self.min_y() + 1;
31        self.shift_down(offset);
32    }
33
34    pub fn width(&self) -> usize {
35        (self.max_x() - self.min_x() + 1) as usize
36    }
37
38    pub fn height(&self) -> usize {
39        (self.max_y() - self.min_y() + 1) as usize
40    }
41
42    pub fn append(&mut self, others: &PrintUnits) {
43        let mut others_copy = others.0.clone();
44        self.0.append(&mut others_copy);
45    }
46
47    fn min_x(&self) -> i64 {
48        self.0
49            .iter()
50            .map(|print_unit| print_unit.x)
51            .min()
52            .unwrap_or(0)
53    }
54
55    fn max_x(&self) -> i64 {
56        self.0
57            .iter()
58            .map(|print_unit| print_unit.x + print_unit.s.len() as i64 - 1)
59            .max()
60            .unwrap_or(0)
61    }
62
63    fn min_y(&self) -> i64 {
64        self.0
65            .iter()
66            .map(|print_unit| print_unit.y)
67            .min()
68            .unwrap_or(0)
69    }
70
71    fn max_y(&self) -> i64 {
72        self.0
73            .iter()
74            .map(|print_unit| print_unit.y)
75            .max()
76            .unwrap_or(0)
77    }
78
79    /// Shift units by `amount` places to the right.
80    pub fn shift_right(&mut self, amount: i64) {
81        for print_unit in self.0.iter_mut() {
82            print_unit.x += amount
83        }
84    }
85
86    /// Shift units down by `amount` places.
87    pub fn shift_down(&mut self, amount: i64) {
88        for print_unit in self.0.iter_mut() {
89            print_unit.y += amount
90        }
91    }
92}
93
94impl From<PrintUnit> for PrintUnits {
95    fn from(print_unit: PrintUnit) -> Self {
96        PrintUnits(vec![print_unit])
97    }
98}
99
100impl fmt::Display for PrintUnits {
101    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
102        let mut sorted = self.0.clone();
103        sorted.sort_by_key(|print_unit| (print_unit.y, print_unit.x));
104
105        if sorted.is_empty() {
106            return Ok(());
107        }
108
109        let mut sorted = PrintUnits(sorted);
110
111        // Start from (0,0)
112        sorted.shift_right(-sorted.min_x());
113        sorted.shift_down(-sorted.min_y());
114        let mut cur_x = 0;
115        let mut cur_y = 0;
116        for print_unit in sorted.0 {
117            // cur_x, cur_y should always be less than or equal to print_unit.x and print_unit.y,
118            // respectively
119            if cur_y > print_unit.y {
120                panic!();
121            }
122
123            if cur_y < print_unit.y {
124                cur_x = 0;
125            }
126
127            if cur_x > print_unit.x {
128                panic!();
129            }
130
131            while cur_y < print_unit.y {
132                writeln!(f)?;
133                cur_y += 1;
134            }
135
136            while cur_x < print_unit.x {
137                write!(f, " ")?;
138                cur_x += 1;
139            }
140
141            f.write_str(&print_unit.s)?;
142
143            cur_x += print_unit.s.len() as i64;
144        }
145
146        Ok(())
147    }
148}
149
150#[derive(Clone, Debug)]
151pub struct PrintUnit {
152    x: i64,
153    y: i64,
154    s: String,
155}
156
157impl PrintUnit {
158    pub fn new(s: &str) -> PrintUnit {
159        PrintUnit {
160            x: 0,
161            y: 0,
162            s: s.to_owned(),
163        }
164    }
165}