use std::future;
use std::time::Duration;
use futures_util::{stream, Stream, StreamExt};
use tokio_stream::wrappers::errors::BroadcastStreamRecvError;
use crate::leb128;
use crate::stream::Event;
static MAGIC_STRING: &str = "ALiS\x01";
#[derive(Default)]
struct EventSerializer(Duration);
pub fn stream<S: Stream<Item = Result<Event, BroadcastStreamRecvError>>>(
stream: S,
) -> impl Stream<Item = Result<Vec<u8>, BroadcastStreamRecvError>> {
let header = stream::once(future::ready(Ok(MAGIC_STRING.into())));
let mut serializer = EventSerializer::default();
let events = stream.map(move |event| event.map(|event| serializer.serialize_event(event)));
header.chain(events)
}
impl EventSerializer {
fn serialize_event(&mut self, event: Event) -> Vec<u8> {
use Event::*;
match event {
Init(last_id, time, size, theme, init) => {
let last_id_bytes = leb128::encode(last_id);
let time_bytes = leb128::encode(time.as_micros() as u64);
let cols_bytes = leb128::encode(size.0);
let rows_bytes = leb128::encode(size.1);
let init_len = init.len() as u32;
let init_len_bytes = leb128::encode(init_len);
let mut msg = vec![0x01];
msg.extend_from_slice(&last_id_bytes);
msg.extend_from_slice(&time_bytes);
msg.extend_from_slice(&cols_bytes);
msg.extend_from_slice(&rows_bytes);
match theme {
Some(theme) => {
msg.push(16);
msg.push(theme.fg.r);
msg.push(theme.fg.g);
msg.push(theme.fg.b);
msg.push(theme.bg.r);
msg.push(theme.bg.g);
msg.push(theme.bg.b);
for color in &theme.palette {
msg.push(color.r);
msg.push(color.g);
msg.push(color.b);
}
}
None => {
msg.push(0);
}
}
msg.extend_from_slice(&init_len_bytes);
msg.extend_from_slice(init.as_bytes());
self.0 = time;
msg
}
Output(id, time, text) => {
let id_bytes = leb128::encode(id);
let time_bytes = leb128::encode(self.rel_time(time));
let text_len = text.len() as u32;
let text_len_bytes = leb128::encode(text_len);
let mut msg = vec![b'o'];
msg.extend_from_slice(&id_bytes);
msg.extend_from_slice(&time_bytes);
msg.extend_from_slice(&text_len_bytes);
msg.extend_from_slice(text.as_bytes());
msg
}
Input(id, time, text) => {
let id_bytes = leb128::encode(id);
let time_bytes = leb128::encode(self.rel_time(time));
let text_len = text.len() as u32;
let text_len_bytes = leb128::encode(text_len);
let mut msg = vec![b'i'];
msg.extend_from_slice(&id_bytes);
msg.extend_from_slice(&time_bytes);
msg.extend_from_slice(&text_len_bytes);
msg.extend_from_slice(text.as_bytes());
msg
}
Resize(id, time, size) => {
let id_bytes = leb128::encode(id);
let time_bytes = leb128::encode(self.rel_time(time));
let cols_bytes = leb128::encode(size.0);
let rows_bytes = leb128::encode(size.1);
let mut msg = vec![b'r'];
msg.extend_from_slice(&id_bytes);
msg.extend_from_slice(&time_bytes);
msg.extend_from_slice(&cols_bytes);
msg.extend_from_slice(&rows_bytes);
msg
}
Marker(id, time, text) => {
let id_bytes = leb128::encode(id);
let time_bytes = leb128::encode(self.rel_time(time));
let text_len = text.len() as u32;
let text_len_bytes = leb128::encode(text_len);
let mut msg = vec![b'm'];
msg.extend_from_slice(&id_bytes);
msg.extend_from_slice(&time_bytes);
msg.extend_from_slice(&text_len_bytes);
msg.extend_from_slice(text.as_bytes());
msg
}
Exit(id, time, status) => {
let id_bytes = leb128::encode(id);
let time_bytes = leb128::encode(self.rel_time(time));
let status_bytes = leb128::encode(status.max(0) as u64);
let mut msg = vec![b'x'];
msg.extend_from_slice(&id_bytes);
msg.extend_from_slice(&time_bytes);
msg.extend_from_slice(&status_bytes);
msg
}
Eot(id, time) => {
let id_bytes = leb128::encode(id);
let time_bytes = leb128::encode(self.rel_time(time));
let mut msg = vec![0x04];
msg.extend_from_slice(&id_bytes);
msg.extend_from_slice(&time_bytes);
msg
}
}
}
fn rel_time(&mut self, time: Duration) -> u64 {
let time = time.max(self.0);
let rel_time = time - self.0;
self.0 = time;
rel_time.as_micros() as u64
}
}
#[cfg(test)]
mod tests {
use rgb::RGB8;
use super::*;
use crate::tty::{TtySize, TtyTheme};
#[test]
fn test_serialize_init_with_theme_and_seed() {
let mut serializer = EventSerializer(Duration::from_millis(0));
let theme = TtyTheme {
fg: rgb(255, 255, 255),
bg: rgb(0, 0, 0),
palette: vec![
rgb(0, 0, 0), rgb(128, 0, 0), rgb(0, 128, 0), rgb(128, 128, 0), rgb(0, 0, 128), rgb(128, 0, 128), rgb(0, 128, 128), rgb(192, 192, 192), rgb(128, 128, 128), rgb(255, 0, 0), rgb(0, 255, 0), rgb(255, 255, 0), rgb(0, 0, 255), rgb(255, 0, 255), rgb(0, 255, 255), rgb(255, 255, 255), ],
};
let event = Event::Init(
42.into(),
Duration::from_micros(1000),
TtySize(180, 24),
Some(theme),
"terminal seed".to_string(),
);
let bytes = serializer.serialize_event(event);
let mut expected = vec![
0x01, 0x2A, 0xE8, 0x07, 0xB4, 0x01, 0x18, 16, 255, 255, 255, 0, 0, 0, ];
expected.extend_from_slice(&[
0, 0, 0, 128, 0, 0, 0, 128, 0, 128, 128, 0, 0, 0, 128, 128, 0, 128, 0, 128, 128, 192, 192, 192, 128, 128, 128, 255, 0, 0, 0, 255, 0, 255, 255, 0, 0, 0, 255, 255, 0, 255, 0, 255, 255, 255, 255, 255, ]);
expected.push(0x0D); expected.extend_from_slice(b"terminal seed");
assert_eq!(bytes, expected);
assert_eq!(serializer.0.as_micros(), 1000);
}
#[test]
fn test_serialize_init_without_theme_nor_seed() {
let mut serializer = EventSerializer::default();
let event = Event::Init(
1.into(),
Duration::from_micros(500),
TtySize(120, 130),
None,
"".to_string(),
);
let bytes = serializer.serialize_event(event);
let expected = vec![
0x01, 0x01, 0xF4, 0x03, 0x78, 0x82, 0x01, 0x00, 0x00, ];
assert_eq!(bytes, expected);
assert_eq!(serializer.0.as_micros(), 500);
}
#[test]
fn test_serialize_output() {
let mut serializer = EventSerializer(Duration::from_micros(1000));
let event = Event::Output(
5.into(),
Duration::from_micros(1200),
"Hello 世界 🌍".to_string(),
);
let bytes = serializer.serialize_event(event);
let mut expected = vec![
b'o', 0x05, 0xC8, 0x01, 0x11, ];
expected.extend_from_slice("Hello 世界 🌍".as_bytes());
assert_eq!(bytes, expected);
assert_eq!(serializer.0.as_micros(), 1200); }
#[test]
fn test_serialize_input() {
let mut serializer = EventSerializer(Duration::from_micros(500));
let event = Event::Input(1000000.into(), Duration::from_micros(750), "x".to_string());
let bytes = serializer.serialize_event(event);
let expected = vec![
b'i', 0xC0, 0x84, 0x3D, 0xFA, 0x01, 0x01, b'x', ];
assert_eq!(bytes, expected);
assert_eq!(serializer.0.as_micros(), 750);
}
#[test]
fn test_serialize_resize() {
let mut serializer = EventSerializer(Duration::from_micros(2000));
let event = Event::Resize(15.into(), Duration::from_micros(2100), TtySize(180, 50));
let bytes = serializer.serialize_event(event);
let expected = vec![
b'r', 0x0F, 0x64, 0xB4, 0x01, 0x32, ];
assert_eq!(bytes, expected);
assert_eq!(serializer.0.as_micros(), 2100);
}
#[test]
fn test_serialize_marker_with_label() {
let mut serializer = EventSerializer(Duration::from_micros(3000));
let event = Event::Marker(
20.into(),
Duration::from_micros(3500),
"checkpoint".to_string(),
);
let bytes = serializer.serialize_event(event);
let expected = vec![
b'm', 0x14, 0xF4, 0x03, 0x0A, ];
let mut expected = expected;
expected.extend_from_slice(b"checkpoint");
assert_eq!(bytes, expected);
assert_eq!(serializer.0.as_micros(), 3500);
}
#[test]
fn test_serialize_marker_without_label() {
let mut serializer = EventSerializer(Duration::from_micros(3000));
let event = Event::Marker(2.into(), Duration::from_micros(3300), "".to_string());
let bytes = serializer.serialize_event(event);
let expected = vec![
b'm', 0x02, 0xAC, 0x02, 0x00, ];
assert_eq!(bytes, expected);
}
#[test]
fn test_serialize_exit_positive_status() {
let mut serializer = EventSerializer(Duration::from_micros(4000));
let event = Event::Exit(25.into(), Duration::from_micros(4200), 0);
let bytes = serializer.serialize_event(event);
let expected = vec![
b'x', 0x19, 0xC8, 0x01, 0x00, ];
assert_eq!(bytes, expected);
assert_eq!(serializer.0.as_micros(), 4200);
}
#[test]
fn test_serialize_exit_negative_status() {
let mut serializer = EventSerializer(Duration::from_micros(5000));
let event = Event::Exit(30.into(), Duration::from_micros(5300), -1);
let bytes = serializer.serialize_event(event);
let expected = vec![
b'x', 0x1E, 0xAC, 0x02, 0x00, ];
assert_eq!(bytes, expected);
assert_eq!(serializer.0.as_micros(), 5300);
}
#[test]
fn test_serialize_eot() {
let mut serializer = EventSerializer(Duration::from_micros(5000));
let event = Event::Eot(30.into(), Duration::from_micros(5300));
let bytes = serializer.serialize_event(event);
let expected = vec![
0x04, 0x1E, 0xAC, 0x02, ];
assert_eq!(bytes, expected);
assert_eq!(serializer.0.as_micros(), 5300);
}
#[test]
fn test_subsequent_event_lower_time() {
let mut serializer = EventSerializer(Duration::from_micros(1000));
let event1 = Event::Output(1.into(), Duration::from_micros(1000), "first".to_string());
let bytes1 = serializer.serialize_event(event1);
assert_eq!(bytes1[2], 0x00); assert_eq!(serializer.0.as_micros(), 1000);
let event2 = Event::Output(2.into(), Duration::from_micros(500), "second".to_string());
let bytes2 = serializer.serialize_event(event2);
assert_eq!(bytes2[2], 0x00); assert_eq!(serializer.0.as_micros(), 1000); }
fn rgb(r: u8, g: u8, b: u8) -> RGB8 {
RGB8::new(r, g, b)
}
}