rm_lines/
line.rs

1use crate::{Color, Parse, Point, Tool};
2
3use nom::{
4    combinator::map,
5    multi::length_count,
6    number::complete::{le_f32, le_u32},
7    sequence::tuple,
8};
9
10/// Data representation of a line in a reMarkable document layer
11///
12/// A `Line` combines a [Tool], a [Color], a size and a series of [Point]s.
13/// It is used to represent a continuous, joined section of [Point]s, such
14/// as a continuous pen stroke.
15#[derive(Debug, PartialEq)]
16pub struct Line {
17    pub tool: Tool,
18    pub color: Color,
19    pub size: f32,
20    pub points: Vec<Point>,
21}
22
23impl<'i> Parse<'i> for Line {
24    /// Attempts to parse a `Line` from a byte sequence
25    ///
26    /// A Line is represented by a series of little-endian 32-bit values.
27    /// 2 of these values serve an unknown purpose at this time, and most
28    /// likely map to functionality like selections, with no obvious or
29    /// useful semantic meaning in the context of a document parser.
30    ///
31    /// Points within a line are represented as a 32-bit point count,
32    /// followed by the raw [Point] values themselves.
33    fn parse(input: &'i [u8]) -> nom::IResult<&'i [u8], Self> {
34        map(
35            tuple((
36                Tool::parse,
37                Color::parse,
38                le_u32, // Unknown/padding
39                le_f32, // Line size (float)
40                le_u32, // Unknown/padding
41                length_count(le_u32, Point::parse),
42            )),
43            |(tool, color, _, size, _, points)| Line {
44                tool,
45                color,
46                size,
47                points,
48            },
49        )(input)
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56
57    #[test]
58    fn test_parse() {
59        let bytes = include_bytes!("../data/test-line.rm");
60
61        let res = Line::parse(bytes);
62        assert!(res.is_ok());
63
64        let (rest, line) = res.unwrap();
65        assert_eq!(rest, &[][..]);
66        assert_eq!(line.tool, Tool::FineLiner);
67        assert_eq!(line.color, Color::Black);
68        assert_eq!(line.size, 2.);
69        assert_eq!(line.points.len(), 309);
70    }
71}