1use crate::cell::Cell;
12use crate::layout::{Position, Rect};
13
14use super::{Bounded, Surface, SurfaceMut};
15
16#[derive(Debug)]
18pub struct View<'a, T: ?Sized> {
19 inner: &'a mut T,
20 bounds: Rect,
21}
22
23impl<'a, T: Bounded + ?Sized> View<'a, T> {
24 pub fn new(inner: &'a mut T, bounds: impl Into<Rect>) -> Self {
28 let bounds = inner.bounds().intersection(bounds.into());
29 Self { inner, bounds }
30 }
31
32 pub fn inner_mut(&mut self) -> &mut T {
35 self.inner
36 }
37}
38
39impl<T: Bounded + ?Sized> Bounded for View<'_, T> {
40 fn bounds(&self) -> Rect {
41 self.bounds
42 }
43}
44
45impl<T: Surface + ?Sized> Surface for View<'_, T> {
46 fn cell(&self, pos: Position) -> Option<&Cell> {
47 if self.bounds.contains(pos) {
48 self.inner.cell(pos)
49 } else {
50 None
51 }
52 }
53}
54
55impl<T: SurfaceMut + ?Sized> SurfaceMut for View<'_, T> {
56 fn set_cell(&mut self, pos: Position, cell: &Cell) {
57 if self.bounds.contains(pos) {
58 self.inner.set_cell(pos, cell);
59 }
60 }
61
62 fn cell_mut(&mut self, pos: Position) -> Option<&mut Cell> {
63 if self.bounds.contains(pos) {
64 self.inner.cell_mut(pos)
65 } else {
66 None
67 }
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74 use crate::buffer::Buffer;
75 use crate::cell::Cell;
76
77 #[test]
78 fn view_clips_writes_outside_bounds() {
79 let mut buf = Buffer::new(10, 5);
80 {
81 let mut v = View::new(&mut buf, Rect::new(2, 1, 3, 2));
82 v.set_cell(Position::new(2, 1), &Cell::narrow("A")); v.set_cell(Position::new(0, 0), &Cell::narrow("B")); v.set_cell(Position::new(5, 1), &Cell::narrow("C")); }
86 assert_eq!(buf.cell(Position::new(2, 1)).unwrap().content(), "A");
87 assert!(buf.cell(Position::new(0, 0)).unwrap().is_blank());
88 assert!(buf.cell(Position::new(5, 1)).unwrap().is_blank());
89 }
90
91 #[test]
92 fn view_clips_reads_outside_bounds() {
93 let mut buf = Buffer::new(10, 5);
94 buf.set_cell(Position::new(2, 1), &Cell::narrow("A"));
95 buf.set_cell(Position::new(0, 0), &Cell::narrow("B"));
96 let mut buf2 = buf.clone();
97 let v = View::new(&mut buf2, Rect::new(2, 1, 3, 2));
98 assert_eq!(v.cell(Position::new(2, 1)).unwrap().content(), "A");
99 assert!(v.cell(Position::new(0, 0)).is_none());
100 }
101
102 #[test]
103 fn view_clips_to_inner_bounds() {
104 let mut buf = Buffer::new(5, 3);
105 let v = View::new(&mut buf, Rect::new(3, 1, 10, 10));
106 assert_eq!(v.bounds(), Rect::new(3, 1, 2, 2));
108 }
109}