Skip to main content

pdf_lib_rs/core/parser/
byte_stream.rs

1use crate::core::syntax::CharCodes;
2
3/// Position information in the byte stream.
4#[derive(Debug, Clone, Copy)]
5pub struct Position {
6    pub line: usize,
7    pub column: usize,
8    pub offset: usize,
9}
10
11/// A cursor over a byte slice for PDF parsing.
12pub struct ByteStream<'a> {
13    bytes: &'a [u8],
14    idx: usize,
15    line: usize,
16    column: usize,
17}
18
19impl<'a> ByteStream<'a> {
20    pub fn of(bytes: &'a [u8]) -> Self {
21        ByteStream {
22            bytes,
23            idx: 0,
24            line: 0,
25            column: 0,
26        }
27    }
28
29    pub fn move_to(&mut self, offset: usize) {
30        self.idx = offset;
31    }
32
33    #[allow(clippy::should_implement_trait)]
34    pub fn next(&mut self) -> Option<u8> {
35        if self.idx >= self.bytes.len() {
36            return None;
37        }
38        let byte = self.bytes[self.idx];
39        self.idx += 1;
40        if byte == CharCodes::Newline {
41            self.line += 1;
42            self.column = 0;
43        } else {
44            self.column += 1;
45        }
46        Some(byte)
47    }
48
49    pub fn peek(&self) -> Option<u8> {
50        self.bytes.get(self.idx).copied()
51    }
52
53    pub fn peek_ahead(&self, steps: usize) -> Option<u8> {
54        self.bytes.get(self.idx + steps).copied()
55    }
56
57    pub fn done(&self) -> bool {
58        self.idx >= self.bytes.len()
59    }
60
61    pub fn offset(&self) -> usize {
62        self.idx
63    }
64
65    pub fn slice(&self, start: usize, end: usize) -> &'a [u8] {
66        &self.bytes[start..end.min(self.bytes.len())]
67    }
68
69    pub fn position(&self) -> Position {
70        Position {
71            line: self.line,
72            column: self.column,
73            offset: self.idx,
74        }
75    }
76
77    pub fn remaining(&self) -> &'a [u8] {
78        &self.bytes[self.idx..]
79    }
80}