lib_ruby_parser/source/
decoded_input.rs

1use crate::source::SourceLine;
2
3/// Decoded input
4#[derive(Debug, Default)]
5#[repr(C)]
6pub struct DecodedInput {
7    /// Name of the input
8    pub name: String,
9
10    /// Lines list
11    pub lines: Vec<SourceLine>,
12
13    /// Decoded bytes
14    pub bytes: Vec<u8>,
15}
16
17impl DecodedInput {
18    /// Constructs empty DecodedInput with given name
19    pub fn named<T>(name: T) -> Self
20    where
21        T: Into<String>,
22    {
23        Self {
24            name: name.into(),
25            ..Default::default()
26        }
27    }
28
29    /// Converts itself into owned vector of bytes
30    pub fn into_bytes(self) -> Vec<u8> {
31        self.bytes
32    }
33
34    pub(crate) fn take_bytes(&mut self) -> Vec<u8> {
35        std::mem::take(&mut self.bytes)
36    }
37
38    /// Populates `Input` with a given byte array
39    pub fn update_bytes(&mut self, bytes: Vec<u8>) {
40        let mut line = SourceLine {
41            start: 0,
42            end: 0,
43            ends_with_eof: true,
44        };
45        let mut lines = vec![];
46
47        for (idx, c) in bytes.iter().enumerate() {
48            line.end = idx + 1;
49            if *c == b'\n' {
50                line.ends_with_eof = false;
51                lines.push(line);
52                line = SourceLine {
53                    start: idx + 1,
54                    end: 0,
55                    ends_with_eof: true,
56                }
57            }
58        }
59        line.end = bytes.len();
60        line.ends_with_eof = true;
61        lines.push(line);
62
63        self.bytes = bytes;
64        self.lines = lines;
65    }
66
67    /// Returns (line, col) pair for a given byte offset.
68    ///
69    /// Returns None if given offset is out of range.
70    pub fn line_col_for_pos(&self, mut pos: usize) -> Option<(usize, usize)> {
71        if pos == self.len() {
72            // EOF loc
73            let last_line = self.lines.last()?;
74            return Some((self.lines.len() - 1, last_line.len()));
75        }
76
77        for (lineno, line) in self.lines.iter().enumerate() {
78            if line.len() > pos {
79                return Some((lineno, pos));
80            } else {
81                pos -= line.len()
82            }
83        }
84
85        None
86    }
87
88    pub(crate) fn line_at(&self, idx: usize) -> &SourceLine {
89        &self.lines[idx]
90    }
91
92    pub(crate) fn substr_at(&self, start: usize, end: usize) -> Option<&[u8]> {
93        if start <= end && end <= self.bytes.len() {
94            Some(&self.bytes[start..end])
95        } else {
96            None
97        }
98    }
99
100    pub(crate) fn len(&self) -> usize {
101        self.bytes.len()
102    }
103
104    /// Returns raw bytes after decoding
105    pub fn as_shared_bytes(&self) -> &[u8] {
106        self.bytes.as_slice()
107    }
108}