Skip to content

Commit

Permalink
feat(cell): add EMPTY and (const) new method (#1143)
Browse files Browse the repository at this point in the history
This simplifies calls to `Buffer::filled` in tests.
  • Loading branch information
EdJoPaTo authored May 25, 2024
1 parent 8cfc316 commit 7a48c5b
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 131 deletions.
6 changes: 2 additions & 4 deletions src/backend/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,8 +329,7 @@ mod tests {
#[test]
fn draw() {
let mut backend = TestBackend::new(10, 2);
let mut cell = Cell::default();
cell.set_symbol("a");
let cell = Cell::new("a");
backend.draw([(0, 0, &cell)].into_iter()).unwrap();
backend.draw([(0, 1, &cell)].into_iter()).unwrap();
backend.assert_buffer_lines(["a "; 2]);
Expand Down Expand Up @@ -366,8 +365,7 @@ mod tests {
#[test]
fn clear() {
let mut backend = TestBackend::new(4, 2);
let mut cell = Cell::default();
cell.set_symbol("a");
let cell = Cell::new("a");
backend.draw([(0, 0, &cell)].into_iter()).unwrap();
backend.draw([(0, 1, &cell)].into_iter()).unwrap();
backend.clear().unwrap();
Expand Down
158 changes: 50 additions & 108 deletions src/buffer/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ impl Buffer {
/// Returns a Buffer with all cells set to the default one
#[must_use]
pub fn empty(area: Rect) -> Self {
Self::filled(area, &Cell::default())
Self::filled(area, &Cell::EMPTY)
}

/// Returns a Buffer with all cells initialized with the attributes of the given Cell
Expand Down Expand Up @@ -278,7 +278,7 @@ impl Buffer {
if self.content.len() > length {
self.content.truncate(length);
} else {
self.content.resize(length, Cell::default());
self.content.resize(length, Cell::EMPTY);
}
self.area = area;
}
Expand All @@ -293,7 +293,7 @@ impl Buffer {
/// Merge an other buffer into this one
pub fn merge(&mut self, other: &Self) {
let area = self.area.union(other.area);
self.content.resize(area.area() as usize, Cell::default());
self.content.resize(area.area() as usize, Cell::EMPTY);

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

use super::*;

fn cell(s: &str) -> Cell {
let mut cell = Cell::default();
cell.set_symbol(s);
cell
}

#[test]
fn debug_empty_buffer() {
let buffer = Buffer::empty(Rect::ZERO);
Expand Down Expand Up @@ -749,25 +743,25 @@ mod tests {
let prev = Buffer::empty(area);
let next = Buffer::empty(area);
let diff = prev.diff(&next);
assert_eq!(diff, vec![]);
assert_eq!(diff, []);
}

#[test]
fn diff_empty_filled() {
let area = Rect::new(0, 0, 40, 40);
let prev = Buffer::empty(area);
let next = Buffer::filled(area, Cell::default().set_symbol("a"));
let next = Buffer::filled(area, &Cell::new("a"));
let diff = prev.diff(&next);
assert_eq!(diff.len(), 40 * 40);
}

#[test]
fn diff_filled_filled() {
let area = Rect::new(0, 0, 40, 40);
let prev = Buffer::filled(area, Cell::default().set_symbol("a"));
let next = Buffer::filled(area, Cell::default().set_symbol("a"));
let prev = Buffer::filled(area, &Cell::new("a"));
let next = Buffer::filled(area, &Cell::new("a"));
let diff = prev.diff(&next);
assert_eq!(diff, vec![]);
assert_eq!(diff, []);
}

#[test]
Expand All @@ -789,35 +783,36 @@ mod tests {
let diff = prev.diff(&next);
assert_eq!(
diff,
vec![
(2, 1, &cell("I")),
(3, 1, &cell("T")),
(4, 1, &cell("L")),
(5, 1, &cell("E")),
[
(2, 1, &Cell::new("I")),
(3, 1, &Cell::new("T")),
(4, 1, &Cell::new("L")),
(5, 1, &Cell::new("E")),
]
);
}

#[test]
#[rustfmt::skip]
fn diff_multi_width() {
#[rustfmt::skip]
let prev = Buffer::with_lines([
"┌Title─┐ ",
"└──────┘ ",
]);
#[rustfmt::skip]
let next = Buffer::with_lines([
"┌称号──┐ ",
"└──────┘ ",
]);
let diff = prev.diff(&next);
assert_eq!(
diff,
vec![
(1, 0, &cell("称")),
[
(1, 0, &Cell::new("称")),
// Skipped "i"
(3, 0, &cell("号")),
(3, 0, &Cell::new("号")),
// Skipped "l"
(5, 0, &cell("─")),
(5, 0, &Cell::new("─")),
]
);
}
Expand All @@ -830,7 +825,11 @@ mod tests {
let diff = prev.diff(&next);
assert_eq!(
diff,
vec![(1, 0, &cell("─")), (2, 0, &cell("称")), (4, 0, &cell("号")),]
[
(1, 0, &Cell::new("─")),
(2, 0, &Cell::new("称")),
(4, 0, &Cell::new("号")),
]
);
}

Expand All @@ -843,67 +842,33 @@ mod tests {
}

let diff = prev.diff(&next);
assert_eq!(diff, vec![(0, 0, &cell("4"))],);
}

#[test]
fn merge() {
let mut one = Buffer::filled(
Rect {
x: 0,
y: 0,
width: 2,
height: 2,
},
Cell::default().set_symbol("1"),
);
let two = Buffer::filled(
Rect {
x: 0,
y: 2,
width: 2,
height: 2,
},
Cell::default().set_symbol("2"),
);
one.merge(&two);
assert_eq!(one, Buffer::with_lines(["11", "11", "22", "22"]));
assert_eq!(diff, [(0, 0, &Cell::new("4"))],);
}

#[test]
fn merge2() {
let mut one = Buffer::filled(
Rect {
x: 2,
y: 2,
width: 2,
height: 2,
},
Cell::default().set_symbol("1"),
);
let two = Buffer::filled(
Rect {
x: 0,
y: 0,
width: 2,
height: 2,
},
Cell::default().set_symbol("2"),
);
#[rstest]
#[case(Rect::new(0, 0, 2, 2), Rect::new(0, 2, 2, 2), ["11", "11", "22", "22"])]
#[case(Rect::new(2, 2, 2, 2), Rect::new(0, 0, 2, 2), ["22 ", "22 ", " 11", " 11"])]
fn merge<'line, Lines>(#[case] one: Rect, #[case] two: Rect, #[case] expected: Lines)
where
Lines: IntoIterator,
Lines::Item: Into<Line<'line>>,
{
let mut one = Buffer::filled(one, &Cell::new("1"));
let two = Buffer::filled(two, &Cell::new("2"));
one.merge(&two);
assert_eq!(one, Buffer::with_lines(["22 ", "22 ", " 11", " 11"]));
assert_eq!(one, Buffer::with_lines(expected));
}

#[test]
fn merge3() {
fn merge_with_offset() {
let mut one = Buffer::filled(
Rect {
x: 3,
y: 3,
width: 2,
height: 2,
},
Cell::default().set_symbol("1"),
&Cell::new("1"),
);
let two = Buffer::filled(
Rect {
Expand All @@ -912,54 +877,31 @@ mod tests {
width: 3,
height: 4,
},
Cell::default().set_symbol("2"),
&Cell::new("2"),
);
one.merge(&two);
let mut merged = Buffer::with_lines(["222 ", "222 ", "2221", "2221"]);
merged.area = Rect {
let mut expected = Buffer::with_lines(["222 ", "222 ", "2221", "2221"]);
expected.area = Rect {
x: 1,
y: 1,
width: 4,
height: 4,
};
assert_eq!(one, merged);
}

#[test]
fn merge_skip() {
let mut one = Buffer::filled(
Rect {
x: 0,
y: 0,
width: 2,
height: 2,
},
Cell::default().set_symbol("1"),
);
let two = Buffer::filled(
Rect {
x: 0,
y: 1,
width: 2,
height: 2,
},
Cell::default().set_symbol("2").set_skip(true),
);
one.merge(&two);
let skipped: Vec<bool> = one.content().iter().map(|c| c.skip).collect();
assert_eq!(skipped, vec![false, false, true, true, true, true]);
assert_eq!(one, expected);
}

#[test]
fn merge_skip2() {
#[rstest]
#[case(false, true, [false, false, true, true, true, true])]
#[case(true, false, [true, true, false, false, false, false])]
fn merge_skip(#[case] one: bool, #[case] two: bool, #[case] expected: [bool; 6]) {
let mut one = Buffer::filled(
Rect {
x: 0,
y: 0,
width: 2,
height: 2,
},
Cell::default().set_symbol("1").set_skip(true),
Cell::new("1").set_skip(one),
);
let two = Buffer::filled(
Rect {
Expand All @@ -968,11 +910,11 @@ mod tests {
width: 2,
height: 2,
},
Cell::default().set_symbol("2"),
Cell::new("2").set_skip(two),
);
one.merge(&two);
let skipped: Vec<bool> = one.content().iter().map(|c| c.skip).collect();
assert_eq!(skipped, vec![true, true, false, false, false, false]);
let skipped = one.content().iter().map(|c| c.skip).collect::<Vec<_>>();
assert_eq!(skipped, expected);
}

#[test]
Expand Down
39 changes: 28 additions & 11 deletions src/buffer/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,27 @@ pub struct Cell {
}

impl Cell {
/// An empty `Cell`
pub const EMPTY: Self = Self::new(" ");

/// Creates a new `Cell` with the given symbol.
///
/// This works at compile time and puts the symbol onto the stack. Fails to build when the
/// symbol doesnt fit onto the stack and requires to be placed on the heap. Use
/// `Self::default().set_symbol()` in that case. See [`CompactString::new_inline`] for more
/// details on this.
pub const fn new(symbol: &str) -> Self {
Self {
symbol: CompactString::new_inline(symbol),
fg: Color::Reset,
bg: Color::Reset,
#[cfg(feature = "underline-color")]
underline_color: Color::Reset,
modifier: Modifier::empty(),
skip: false,
}
}

/// Gets the symbol of the cell.
#[must_use]
pub fn symbol(&self) -> &str {
Expand Down Expand Up @@ -108,7 +129,7 @@ impl Cell {
self
}

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

impl Default for Cell {
fn default() -> Self {
Self {
symbol: CompactString::new_inline(" "),
fg: Color::Reset,
bg: Color::Reset,
#[cfg(feature = "underline-color")]
underline_color: Color::Reset,
modifier: Modifier::empty(),
skip: false,
}
Self::EMPTY
}
}

Expand All @@ -142,11 +155,15 @@ mod tests {

#[test]
fn symbol_field() {
let mut cell = Cell::default();
let mut cell = Cell::EMPTY;
assert_eq!(cell.symbol(), " ");
cell.set_symbol("あ"); // Multi-byte character
assert_eq!(cell.symbol(), "あ");
cell.set_symbol("👨‍👩‍👧‍👦"); // Multiple code units combined with ZWJ
assert_eq!(cell.symbol(), "👨‍👩‍👧‍👦");

// above Cell::EMPTY is put into a mutable variable and is changed then.
// While this looks like it might change the constant, it actually doesnt:
assert_eq!(Cell::EMPTY.symbol(), " ");
}
}
Loading

0 comments on commit 7a48c5b

Please sign in to comment.