1use crate::cell::{Cell, CellFlags};
10use crate::color::Color;
11use crate::cursor::CursorShape;
12use crate::damage::ScrollOp;
13use core::num::NonZeroU32;
14use std::collections::BTreeMap;
15
16const MAGIC: [u8; 2] = *b"JT";
18const VERSION: u8 = 4; pub const WIRE_VERSION: u8 = VERSION;
23
24#[derive(Clone, Copy, PartialEq, Eq, Debug)]
26pub enum FrameKind {
27 Full,
29 Partial,
31}
32
33#[derive(Clone, PartialEq, Eq, Debug)]
43pub struct Span {
44 pub line: u16,
45 pub left: u16,
46 pub right: u16,
47 pub cells: Vec<Cell>,
48 pub combining: BTreeMap<usize, NonZeroU32>,
49 pub links: BTreeMap<usize, NonZeroU32>,
50}
51
52#[derive(Clone, PartialEq, Eq, Debug)]
57pub struct Frame {
58 pub cols: u16,
59 pub rows: u16,
60 pub kind: FrameKind,
61 pub cursor_row: u16,
66 pub cursor_col: u16,
67 pub cursor_visible: bool,
68 pub cursor_shape: CursorShape,
71 pub cursor_blink: bool,
72 pub scroll: Option<ScrollOp>,
73 pub spans: Vec<Span>,
74 pub side_table: Vec<Vec<char>>,
75 pub link_table: Vec<String>,
76}
77
78#[derive(Clone, Copy, PartialEq, Eq, Debug)]
80pub enum DecodeError {
81 Truncated,
83 BadMagic,
85 BadVersion(u8),
87 BadTag,
89 BadSpan,
91}
92
93pub fn encode(frame: &Frame) -> Vec<u8> {
95 let mut out = Vec::new();
96 out.extend_from_slice(&MAGIC);
97 out.push(VERSION);
98 out.push(frame.scroll.is_some() as u8);
99 out.push(match frame.kind {
100 FrameKind::Full => 0,
101 FrameKind::Partial => 1,
102 });
103 out.extend_from_slice(&frame.cols.to_le_bytes());
104 out.extend_from_slice(&frame.rows.to_le_bytes());
105 out.extend_from_slice(&frame.cursor_row.to_le_bytes());
106 out.extend_from_slice(&frame.cursor_col.to_le_bytes());
107 out.push(frame.cursor_visible as u8);
108 out.push(match frame.cursor_shape {
109 CursorShape::Block => 0,
110 CursorShape::Underline => 1,
111 CursorShape::Bar => 2,
112 });
113 out.push(frame.cursor_blink as u8);
114 if let Some(s) = frame.scroll {
115 out.extend_from_slice(&(s.top as u16).to_le_bytes());
116 out.extend_from_slice(&(s.bottom as u16).to_le_bytes());
117 out.extend_from_slice(&(s.count as i16).to_le_bytes());
118 }
119 out.extend_from_slice(&(frame.spans.len() as u16).to_le_bytes());
120 for span in &frame.spans {
121 out.extend_from_slice(&span.line.to_le_bytes());
122 out.extend_from_slice(&span.left.to_le_bytes());
123 out.extend_from_slice(&span.right.to_le_bytes());
124 for (col, cell) in span.cells.iter().enumerate() {
125 let extra = span.combining.get(&col).map_or(0, |n| n.get() as u16);
128 let link = span.links.get(&col).map_or(0, |n| n.get() as u16);
129 out.extend_from_slice(&encode_cell_record(cell, extra, link));
130 }
131 }
132 out.extend_from_slice(&(frame.side_table.len() as u16).to_le_bytes());
133 for cluster in &frame.side_table {
134 out.extend_from_slice(&(cluster.len() as u16).to_le_bytes());
135 for &ch in cluster {
136 out.extend_from_slice(&(ch as u32).to_le_bytes());
137 }
138 }
139 out.extend_from_slice(&(frame.link_table.len() as u16).to_le_bytes());
141 for uri in &frame.link_table {
142 out.extend_from_slice(&(uri.len() as u16).to_le_bytes());
143 out.extend_from_slice(uri.as_bytes());
144 }
145 out
146}
147
148pub const CELL_RECORD_LEN: usize = 18;
151
152pub fn encode_cell_record(cell: &Cell, extra: u16, link: u16) -> [u8; CELL_RECORD_LEN] {
166 let mut r = [0u8; CELL_RECORD_LEN];
167 r[0..4].copy_from_slice(&(cell.c() as u32).to_le_bytes());
168 r[4..8].copy_from_slice(&encode_color(cell.fg()).to_le_bytes());
169 r[8..12].copy_from_slice(&encode_color(cell.bg()).to_le_bytes());
170 r[12..14].copy_from_slice(&cell.flags().bits().to_le_bytes());
171 r[14..16].copy_from_slice(&extra.to_le_bytes());
172 r[16..18].copy_from_slice(&link.to_le_bytes());
173 r
174}
175
176pub fn encode_color(c: Color) -> u32 {
184 match c {
185 Color::Default => 0,
186 Color::Indexed(i) => (1 << 24) | i as u32,
187 Color::Rgb(r, g, b) => (2 << 24) | (r as u32) << 16 | (g as u32) << 8 | b as u32,
188 }
189}
190
191pub fn decode(bytes: &[u8]) -> Result<Frame, DecodeError> {
193 let mut r = Reader::new(bytes);
194 if r.take(2)? != MAGIC {
195 return Err(DecodeError::BadMagic);
196 }
197 let version = r.u8()?;
198 if version != VERSION {
199 return Err(DecodeError::BadVersion(version));
200 }
201 let has_scroll = r.u8()? != 0;
202 let kind = match r.u8()? {
203 0 => FrameKind::Full,
204 1 => FrameKind::Partial,
205 _ => return Err(DecodeError::BadTag),
206 };
207 let cols = r.u16()?;
208 let rows = r.u16()?;
209 let cursor_row = r.u16()?;
210 let cursor_col = r.u16()?;
211 let cursor_visible = r.u8()? != 0;
212 let cursor_shape = match r.u8()? {
213 0 => CursorShape::Block,
214 1 => CursorShape::Underline,
215 2 => CursorShape::Bar,
216 _ => return Err(DecodeError::BadTag),
217 };
218 let cursor_blink = r.u8()? != 0;
219 let scroll = if has_scroll {
220 let top = r.u16()? as usize;
221 let bottom = r.u16()? as usize;
222 let count = (r.u16()? as i16) as isize;
223 Some(ScrollOp { top, bottom, count })
224 } else {
225 None
226 };
227 let span_count = r.u16()?;
228 let mut spans = Vec::with_capacity(span_count as usize);
229 for _ in 0..span_count {
230 let line = r.u16()?;
231 let left = r.u16()?;
232 let right = r.u16()?;
233 if right < left {
234 return Err(DecodeError::BadSpan);
235 }
236 let n = right as usize - left as usize + 1;
241 let mut cells = Vec::with_capacity(n);
242 let mut combining = BTreeMap::new();
243 let mut links = BTreeMap::new();
244 for col in 0..n {
245 let (cell, extra, link) = decode_cell(&mut r)?;
246 if let Some(idx) = NonZeroU32::new(extra as u32) {
247 combining.insert(col, idx);
248 }
249 if let Some(idx) = NonZeroU32::new(link as u32) {
250 links.insert(col, idx);
251 }
252 cells.push(cell);
253 }
254 spans.push(Span {
255 line,
256 left,
257 right,
258 cells,
259 combining,
260 links,
261 });
262 }
263 let side_table_count = r.u16()?;
264 let mut side_table = Vec::with_capacity(side_table_count as usize);
265 for _ in 0..side_table_count {
266 let len = r.u16()?;
267 let mut cluster = Vec::with_capacity(len as usize);
268 for _ in 0..len {
269 cluster.push(char::from_u32(r.u32()?).ok_or(DecodeError::BadTag)?);
270 }
271 side_table.push(cluster);
272 }
273 let link_count = r.u16()?;
274 let mut link_table = Vec::with_capacity(link_count as usize);
275 for _ in 0..link_count {
276 let len = r.u16()? as usize;
277 let bytes = r.take(len)?;
278 link_table.push(String::from_utf8_lossy(bytes).into_owned());
279 }
280 Ok(Frame {
281 cols,
282 rows,
283 kind,
284 cursor_row,
285 cursor_col,
286 cursor_visible,
287 cursor_shape,
288 cursor_blink,
289 scroll,
290 spans,
291 side_table,
292 link_table,
293 })
294}
295
296fn decode_cell(r: &mut Reader) -> Result<(Cell, u16, u16), DecodeError> {
301 let c = char::from_u32(r.u32()?).ok_or(DecodeError::BadTag)?;
302 let fg = decode_color(r.u32()?)?;
303 let bg = decode_color(r.u32()?)?;
304 let flags = CellFlags::from_bits_retain(r.u16()?);
305 let extra = r.u16()?;
306 let link = r.u16()?;
307 let mut cell = Cell::from_parts(c, fg, bg, flags);
308 cell.set_combined(extra != 0);
309 cell.set_linked(link != 0);
310 Ok((cell, extra, link))
311}
312
313fn decode_color(v: u32) -> Result<Color, DecodeError> {
315 let payload = v & 0x00FF_FFFF;
316 match v >> 24 {
317 0 => Ok(Color::Default),
318 1 => Ok(Color::Indexed(payload as u8)),
319 2 => Ok(Color::Rgb(
320 (payload >> 16) as u8,
321 (payload >> 8) as u8,
322 payload as u8,
323 )),
324 _ => Err(DecodeError::BadTag),
325 }
326}
327
328struct Reader<'a> {
330 bytes: &'a [u8],
331 pos: usize,
332}
333
334impl<'a> Reader<'a> {
335 fn new(bytes: &'a [u8]) -> Self {
336 Reader { bytes, pos: 0 }
337 }
338
339 fn take(&mut self, n: usize) -> Result<&'a [u8], DecodeError> {
340 let end = self.pos.checked_add(n).ok_or(DecodeError::Truncated)?;
341 let slice = self
342 .bytes
343 .get(self.pos..end)
344 .ok_or(DecodeError::Truncated)?;
345 self.pos = end;
346 Ok(slice)
347 }
348
349 fn u8(&mut self) -> Result<u8, DecodeError> {
350 Ok(self.take(1)?[0])
351 }
352
353 fn u16(&mut self) -> Result<u16, DecodeError> {
354 let b = self.take(2)?;
355 Ok(u16::from_le_bytes([b[0], b[1]]))
356 }
357
358 fn u32(&mut self) -> Result<u32, DecodeError> {
359 let b = self.take(4)?;
360 Ok(u32::from_le_bytes([b[0], b[1], b[2], b[3]]))
361 }
362}