1use unicode_width::UnicodeWidthChar as _;
2
3const CONTENT_BYTES: usize = 22;
5
6const IS_WIDE: u8 = 0b1000_0000;
7const IS_WIDE_CONTINUATION: u8 = 0b0100_0000;
8const LEN_BITS: u8 = 0b0001_1111;
9
10#[derive(Clone, Debug, Eq)]
12pub struct Cell {
13 contents: [u8; CONTENT_BYTES],
14 len: u8,
15 attrs: crate::attrs::Attrs,
16}
17const _: () = assert!(std::mem::size_of::<Cell>() == 32);
18
19impl PartialEq<Self> for Cell {
20 fn eq(&self, other: &Self) -> bool {
21 if self.len != other.len {
22 return false;
23 }
24 if self.attrs != other.attrs {
25 return false;
26 }
27 let len = self.len();
28 self.contents[..len] == other.contents[..len]
29 }
30}
31
32impl Cell {
33 pub(crate) fn new() -> Self {
34 Self {
35 contents: Default::default(),
36 len: 0,
37 attrs: crate::attrs::Attrs::default(),
38 }
39 }
40
41 fn len(&self) -> usize {
42 usize::from(self.len & LEN_BITS)
43 }
44
45 pub(crate) fn set(&mut self, c: char, a: crate::attrs::Attrs) {
46 self.len = 0;
47 self.append_char(0, c);
48 self.set_wide(c.width().unwrap_or(1) > 1);
52 self.attrs = a;
53 }
54
55 pub(crate) fn append(&mut self, c: char) {
56 let len = self.len();
57 if len >= CONTENT_BYTES - 4 {
58 return;
59 }
60 if len == 0 {
61 self.contents[0] = b' ';
62 self.len += 1;
63 }
64
65 self.append_char(self.len(), c);
67 }
68
69 fn append_char(&mut self, start: usize, c: char) {
72 c.encode_utf8(&mut self.contents[start..]);
73 self.len += u8::try_from(c.len_utf8()).unwrap();
74 }
75
76 pub(crate) fn clear(&mut self, attrs: crate::attrs::Attrs) {
77 self.len = 0;
78 self.attrs = attrs;
79 }
80
81 #[allow(clippy::missing_panics_doc)]
88 #[must_use]
89 pub fn contents(&self) -> &str {
90 std::str::from_utf8(&self.contents[..self.len()]).unwrap()
91 }
92
93 #[must_use]
95 pub fn has_contents(&self) -> bool {
96 self.len() > 0
97 }
98
99 #[must_use]
101 pub fn is_wide(&self) -> bool {
102 self.len & IS_WIDE != 0
103 }
104
105 #[must_use]
109 pub fn is_wide_continuation(&self) -> bool {
110 self.len & IS_WIDE_CONTINUATION != 0
111 }
112
113 fn set_wide(&mut self, wide: bool) {
114 if wide {
115 self.len |= IS_WIDE;
116 } else {
117 self.len &= !IS_WIDE;
118 }
119 }
120
121 pub(crate) fn set_wide_continuation(&mut self, wide: bool) {
122 if wide {
123 self.len |= IS_WIDE_CONTINUATION;
124 } else {
125 self.len &= !IS_WIDE_CONTINUATION;
126 }
127 }
128
129 pub(crate) fn attrs(&self) -> &crate::attrs::Attrs {
130 &self.attrs
131 }
132
133 #[must_use]
135 pub fn fgcolor(&self) -> crate::Color {
136 self.attrs.fgcolor
137 }
138
139 #[must_use]
141 pub fn bgcolor(&self) -> crate::Color {
142 self.attrs.bgcolor
143 }
144
145 #[must_use]
148 pub fn bold(&self) -> bool {
149 self.attrs.bold()
150 }
151
152 #[must_use]
155 pub fn dim(&self) -> bool {
156 self.attrs.dim()
157 }
158
159 #[must_use]
162 pub fn italic(&self) -> bool {
163 self.attrs.italic()
164 }
165
166 #[must_use]
169 pub fn underline(&self) -> bool {
170 self.attrs.underline()
171 }
172
173 #[must_use]
176 pub fn inverse(&self) -> bool {
177 self.attrs.inverse()
178 }
179}