ttyrec/
frame.rs

1/// Represents a single ttyrec frame.
2///
3/// Ttyrec files are a raw concatenation of frames. Note that the timestamps
4/// in the frame are absolute timestamps, and only the difference between them
5/// is relevant. The base timestamp can be anything (common choices are 0 or
6/// the actual time that the frame was generated).
7///
8/// Frame objects are typically created via the [`Creator`](crate::Creator),
9/// [`Parser`](crate::Parser), or [`Reader`](crate::Reader) classes.
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct Frame {
12    /// Amount of time passed since the start of the ttyrec file.
13    ///
14    /// Note that this is *not* the amount of time since the previous frame.
15    pub time: std::time::Duration,
16
17    /// Bytes emitted at the given time.
18    pub data: Vec<u8>,
19}
20
21impl TryFrom<Frame> for Vec<u8> {
22    type Error = crate::error::Error;
23
24    fn try_from(frame: Frame) -> crate::error::Result<Self> {
25        let secs = u32::try_from(frame.time.as_secs()).map_err(|_| {
26            crate::error::Error::FrameTooLong {
27                input: frame.time.as_secs(),
28            }
29        })?;
30        let micros = frame.time.subsec_micros();
31        let len = u32::try_from(frame.data.len()).map_err(|_| {
32            crate::error::Error::FrameTooBig {
33                input: frame.data.len(),
34            }
35        })?;
36        let mut bytes = vec![];
37        bytes.extend(secs.to_le_bytes().iter());
38        bytes.extend(micros.to_le_bytes().iter());
39        bytes.extend(len.to_le_bytes().iter());
40        bytes.extend(frame.data.iter());
41        Ok(bytes)
42    }
43}
44
45#[cfg(test)]
46#[allow(clippy::unwrap_used)]
47mod test {
48    use super::*;
49
50    #[test]
51    fn test_basic() {
52        let tests = vec![
53            (
54                Frame {
55                    time: std::time::Duration::new(0, 0),
56                    data: vec![],
57                },
58                vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
59            ),
60            (
61                Frame {
62                    time: std::time::Duration::new(38, 123_456_000),
63                    data: b"\x1b[2Jfoobar".to_vec(),
64                },
65                vec![
66                    38, 0, 0, 0, 64, 226, 1, 0, 10, 0, 0, 0, 27, 91, 50, 74,
67                    102, 111, 111, 98, 97, 114,
68                ],
69            ),
70        ];
71        for (frame, bytes) in tests {
72            assert_eq!(Vec::<u8>::try_from(frame).unwrap(), bytes);
73        }
74    }
75}