Skip to content

Commit 7a48c5b

Browse files
authored
feat(cell): add EMPTY and (const) new method (#1143)
This simplifies calls to `Buffer::filled` in tests.
1 parent 8cfc316 commit 7a48c5b

File tree

6 files changed

+84
-131
lines changed

6 files changed

+84
-131
lines changed

src/backend/test.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -329,8 +329,7 @@ mod tests {
329329
#[test]
330330
fn draw() {
331331
let mut backend = TestBackend::new(10, 2);
332-
let mut cell = Cell::default();
333-
cell.set_symbol("a");
332+
let cell = Cell::new("a");
334333
backend.draw([(0, 0, &cell)].into_iter()).unwrap();
335334
backend.draw([(0, 1, &cell)].into_iter()).unwrap();
336335
backend.assert_buffer_lines(["a "; 2]);
@@ -366,8 +365,7 @@ mod tests {
366365
#[test]
367366
fn clear() {
368367
let mut backend = TestBackend::new(4, 2);
369-
let mut cell = Cell::default();
370-
cell.set_symbol("a");
368+
let cell = Cell::new("a");
371369
backend.draw([(0, 0, &cell)].into_iter()).unwrap();
372370
backend.draw([(0, 1, &cell)].into_iter()).unwrap();
373371
backend.clear().unwrap();

src/buffer/buffer.rs

+50-108
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ impl Buffer {
5454
/// Returns a Buffer with all cells set to the default one
5555
#[must_use]
5656
pub fn empty(area: Rect) -> Self {
57-
Self::filled(area, &Cell::default())
57+
Self::filled(area, &Cell::EMPTY)
5858
}
5959

6060
/// Returns a Buffer with all cells initialized with the attributes of the given Cell
@@ -278,7 +278,7 @@ impl Buffer {
278278
if self.content.len() > length {
279279
self.content.truncate(length);
280280
} else {
281-
self.content.resize(length, Cell::default());
281+
self.content.resize(length, Cell::EMPTY);
282282
}
283283
self.area = area;
284284
}
@@ -293,7 +293,7 @@ impl Buffer {
293293
/// Merge an other buffer into this one
294294
pub fn merge(&mut self, other: &Self) {
295295
let area = self.area.union(other.area);
296-
self.content.resize(area.area() as usize, Cell::default());
296+
self.content.resize(area.area() as usize, Cell::EMPTY);
297297

298298
// Move original content to the appropriate space
299299
let size = self.area.area() as usize;
@@ -453,12 +453,6 @@ mod tests {
453453

454454
use super::*;
455455

456-
fn cell(s: &str) -> Cell {
457-
let mut cell = Cell::default();
458-
cell.set_symbol(s);
459-
cell
460-
}
461-
462456
#[test]
463457
fn debug_empty_buffer() {
464458
let buffer = Buffer::empty(Rect::ZERO);
@@ -749,25 +743,25 @@ mod tests {
749743
let prev = Buffer::empty(area);
750744
let next = Buffer::empty(area);
751745
let diff = prev.diff(&next);
752-
assert_eq!(diff, vec![]);
746+
assert_eq!(diff, []);
753747
}
754748

755749
#[test]
756750
fn diff_empty_filled() {
757751
let area = Rect::new(0, 0, 40, 40);
758752
let prev = Buffer::empty(area);
759-
let next = Buffer::filled(area, Cell::default().set_symbol("a"));
753+
let next = Buffer::filled(area, &Cell::new("a"));
760754
let diff = prev.diff(&next);
761755
assert_eq!(diff.len(), 40 * 40);
762756
}
763757

764758
#[test]
765759
fn diff_filled_filled() {
766760
let area = Rect::new(0, 0, 40, 40);
767-
let prev = Buffer::filled(area, Cell::default().set_symbol("a"));
768-
let next = Buffer::filled(area, Cell::default().set_symbol("a"));
761+
let prev = Buffer::filled(area, &Cell::new("a"));
762+
let next = Buffer::filled(area, &Cell::new("a"));
769763
let diff = prev.diff(&next);
770-
assert_eq!(diff, vec![]);
764+
assert_eq!(diff, []);
771765
}
772766

773767
#[test]
@@ -789,35 +783,36 @@ mod tests {
789783
let diff = prev.diff(&next);
790784
assert_eq!(
791785
diff,
792-
vec![
793-
(2, 1, &cell("I")),
794-
(3, 1, &cell("T")),
795-
(4, 1, &cell("L")),
796-
(5, 1, &cell("E")),
786+
[
787+
(2, 1, &Cell::new("I")),
788+
(3, 1, &Cell::new("T")),
789+
(4, 1, &Cell::new("L")),
790+
(5, 1, &Cell::new("E")),
797791
]
798792
);
799793
}
800794

801795
#[test]
802-
#[rustfmt::skip]
803796
fn diff_multi_width() {
797+
#[rustfmt::skip]
804798
let prev = Buffer::with_lines([
805799
"┌Title─┐ ",
806800
"└──────┘ ",
807801
]);
802+
#[rustfmt::skip]
808803
let next = Buffer::with_lines([
809804
"┌称号──┐ ",
810805
"└──────┘ ",
811806
]);
812807
let diff = prev.diff(&next);
813808
assert_eq!(
814809
diff,
815-
vec![
816-
(1, 0, &cell("称")),
810+
[
811+
(1, 0, &Cell::new("称")),
817812
// Skipped "i"
818-
(3, 0, &cell("号")),
813+
(3, 0, &Cell::new("号")),
819814
// Skipped "l"
820-
(5, 0, &cell("─")),
815+
(5, 0, &Cell::new("─")),
821816
]
822817
);
823818
}
@@ -830,7 +825,11 @@ mod tests {
830825
let diff = prev.diff(&next);
831826
assert_eq!(
832827
diff,
833-
vec![(1, 0, &cell("─")), (2, 0, &cell("称")), (4, 0, &cell("号")),]
828+
[
829+
(1, 0, &Cell::new("─")),
830+
(2, 0, &Cell::new("称")),
831+
(4, 0, &Cell::new("号")),
832+
]
834833
);
835834
}
836835

@@ -843,67 +842,33 @@ mod tests {
843842
}
844843

845844
let diff = prev.diff(&next);
846-
assert_eq!(diff, vec![(0, 0, &cell("4"))],);
847-
}
848-
849-
#[test]
850-
fn merge() {
851-
let mut one = Buffer::filled(
852-
Rect {
853-
x: 0,
854-
y: 0,
855-
width: 2,
856-
height: 2,
857-
},
858-
Cell::default().set_symbol("1"),
859-
);
860-
let two = Buffer::filled(
861-
Rect {
862-
x: 0,
863-
y: 2,
864-
width: 2,
865-
height: 2,
866-
},
867-
Cell::default().set_symbol("2"),
868-
);
869-
one.merge(&two);
870-
assert_eq!(one, Buffer::with_lines(["11", "11", "22", "22"]));
845+
assert_eq!(diff, [(0, 0, &Cell::new("4"))],);
871846
}
872847

873-
#[test]
874-
fn merge2() {
875-
let mut one = Buffer::filled(
876-
Rect {
877-
x: 2,
878-
y: 2,
879-
width: 2,
880-
height: 2,
881-
},
882-
Cell::default().set_symbol("1"),
883-
);
884-
let two = Buffer::filled(
885-
Rect {
886-
x: 0,
887-
y: 0,
888-
width: 2,
889-
height: 2,
890-
},
891-
Cell::default().set_symbol("2"),
892-
);
848+
#[rstest]
849+
#[case(Rect::new(0, 0, 2, 2), Rect::new(0, 2, 2, 2), ["11", "11", "22", "22"])]
850+
#[case(Rect::new(2, 2, 2, 2), Rect::new(0, 0, 2, 2), ["22 ", "22 ", " 11", " 11"])]
851+
fn merge<'line, Lines>(#[case] one: Rect, #[case] two: Rect, #[case] expected: Lines)
852+
where
853+
Lines: IntoIterator,
854+
Lines::Item: Into<Line<'line>>,
855+
{
856+
let mut one = Buffer::filled(one, &Cell::new("1"));
857+
let two = Buffer::filled(two, &Cell::new("2"));
893858
one.merge(&two);
894-
assert_eq!(one, Buffer::with_lines(["22 ", "22 ", " 11", " 11"]));
859+
assert_eq!(one, Buffer::with_lines(expected));
895860
}
896861

897862
#[test]
898-
fn merge3() {
863+
fn merge_with_offset() {
899864
let mut one = Buffer::filled(
900865
Rect {
901866
x: 3,
902867
y: 3,
903868
width: 2,
904869
height: 2,
905870
},
906-
Cell::default().set_symbol("1"),
871+
&Cell::new("1"),
907872
);
908873
let two = Buffer::filled(
909874
Rect {
@@ -912,54 +877,31 @@ mod tests {
912877
width: 3,
913878
height: 4,
914879
},
915-
Cell::default().set_symbol("2"),
880+
&Cell::new("2"),
916881
);
917882
one.merge(&two);
918-
let mut merged = Buffer::with_lines(["222 ", "222 ", "2221", "2221"]);
919-
merged.area = Rect {
883+
let mut expected = Buffer::with_lines(["222 ", "222 ", "2221", "2221"]);
884+
expected.area = Rect {
920885
x: 1,
921886
y: 1,
922887
width: 4,
923888
height: 4,
924889
};
925-
assert_eq!(one, merged);
926-
}
927-
928-
#[test]
929-
fn merge_skip() {
930-
let mut one = Buffer::filled(
931-
Rect {
932-
x: 0,
933-
y: 0,
934-
width: 2,
935-
height: 2,
936-
},
937-
Cell::default().set_symbol("1"),
938-
);
939-
let two = Buffer::filled(
940-
Rect {
941-
x: 0,
942-
y: 1,
943-
width: 2,
944-
height: 2,
945-
},
946-
Cell::default().set_symbol("2").set_skip(true),
947-
);
948-
one.merge(&two);
949-
let skipped: Vec<bool> = one.content().iter().map(|c| c.skip).collect();
950-
assert_eq!(skipped, vec![false, false, true, true, true, true]);
890+
assert_eq!(one, expected);
951891
}
952892

953-
#[test]
954-
fn merge_skip2() {
893+
#[rstest]
894+
#[case(false, true, [false, false, true, true, true, true])]
895+
#[case(true, false, [true, true, false, false, false, false])]
896+
fn merge_skip(#[case] one: bool, #[case] two: bool, #[case] expected: [bool; 6]) {
955897
let mut one = Buffer::filled(
956898
Rect {
957899
x: 0,
958900
y: 0,
959901
width: 2,
960902
height: 2,
961903
},
962-
Cell::default().set_symbol("1").set_skip(true),
904+
Cell::new("1").set_skip(one),
963905
);
964906
let two = Buffer::filled(
965907
Rect {
@@ -968,11 +910,11 @@ mod tests {
968910
width: 2,
969911
height: 2,
970912
},
971-
Cell::default().set_symbol("2"),
913+
Cell::new("2").set_skip(two),
972914
);
973915
one.merge(&two);
974-
let skipped: Vec<bool> = one.content().iter().map(|c| c.skip).collect();
975-
assert_eq!(skipped, vec![true, true, false, false, false, false]);
916+
let skipped = one.content().iter().map(|c| c.skip).collect::<Vec<_>>();
917+
assert_eq!(skipped, expected);
976918
}
977919

978920
#[test]

src/buffer/cell.rs

+28-11
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,27 @@ pub struct Cell {
3434
}
3535

3636
impl Cell {
37+
/// An empty `Cell`
38+
pub const EMPTY: Self = Self::new(" ");
39+
40+
/// Creates a new `Cell` with the given symbol.
41+
///
42+
/// This works at compile time and puts the symbol onto the stack. Fails to build when the
43+
/// symbol doesnt fit onto the stack and requires to be placed on the heap. Use
44+
/// `Self::default().set_symbol()` in that case. See [`CompactString::new_inline`] for more
45+
/// details on this.
46+
pub const fn new(symbol: &str) -> Self {
47+
Self {
48+
symbol: CompactString::new_inline(symbol),
49+
fg: Color::Reset,
50+
bg: Color::Reset,
51+
#[cfg(feature = "underline-color")]
52+
underline_color: Color::Reset,
53+
modifier: Modifier::empty(),
54+
skip: false,
55+
}
56+
}
57+
3758
/// Gets the symbol of the cell.
3859
#[must_use]
3960
pub fn symbol(&self) -> &str {
@@ -108,7 +129,7 @@ impl Cell {
108129
self
109130
}
110131

111-
/// Resets the cell to the default state.
132+
/// Resets the cell to the empty state.
112133
pub fn reset(&mut self) {
113134
self.symbol = CompactString::new_inline(" ");
114135
self.fg = Color::Reset;
@@ -124,15 +145,7 @@ impl Cell {
124145

125146
impl Default for Cell {
126147
fn default() -> Self {
127-
Self {
128-
symbol: CompactString::new_inline(" "),
129-
fg: Color::Reset,
130-
bg: Color::Reset,
131-
#[cfg(feature = "underline-color")]
132-
underline_color: Color::Reset,
133-
modifier: Modifier::empty(),
134-
skip: false,
135-
}
148+
Self::EMPTY
136149
}
137150
}
138151

@@ -142,11 +155,15 @@ mod tests {
142155

143156
#[test]
144157
fn symbol_field() {
145-
let mut cell = Cell::default();
158+
let mut cell = Cell::EMPTY;
146159
assert_eq!(cell.symbol(), " ");
147160
cell.set_symbol("あ"); // Multi-byte character
148161
assert_eq!(cell.symbol(), "あ");
149162
cell.set_symbol("👨‍👩‍👧‍👦"); // Multiple code units combined with ZWJ
150163
assert_eq!(cell.symbol(), "👨‍👩‍👧‍👦");
164+
165+
// above Cell::EMPTY is put into a mutable variable and is changed then.
166+
// While this looks like it might change the constant, it actually doesnt:
167+
assert_eq!(Cell::EMPTY.symbol(), " ");
151168
}
152169
}

0 commit comments

Comments
 (0)