1use memchr::{memchr, memrchr};
2
3use crate::reader::Cursor;
4
5#[derive(Debug, Clone, Eq, PartialEq)]
7pub struct Span<'a> {
8 content: &'a str,
9 start_cursor: Cursor,
10 end_cursor: Cursor,
11}
12
13impl<'a> Span<'a> {
14 pub(in crate::reader) fn new(
18 content: &'a str,
19 start_cursor: Cursor,
20 end_cursor: Cursor,
21 ) -> Span {
22 Span {
23 content,
24 start_cursor,
25 end_cursor,
26 }
27 }
28
29 pub fn whole_content(&self) -> &'a str {
33 self.content
34 }
35
36 pub fn content(&self) -> &'a str {
38 &self.content[self.start_cursor.byte_offset()..self.end_cursor.byte_offset()]
39 }
40
41 pub fn content_before(&self) -> &'a str {
43 &self.content[..self.start_cursor.byte_offset()]
44 }
45
46 pub fn content_after(&self) -> &'a str {
48 &self.content[self.end_cursor.byte_offset()..]
49 }
50
51 pub fn start_cursor(&self) -> &Cursor {
53 &self.start_cursor
54 }
55
56 pub fn end_cursor(&self) -> &Cursor {
58 &self.end_cursor
59 }
60
61 pub fn len(&self) -> usize {
63 self.end_cursor.byte_offset() - self.start_cursor.byte_offset()
64 }
65
66 pub fn is_empty(&self) -> bool {
68 self.len() == 0
69 }
70
71 pub fn char_length(&self) -> usize {
73 self.end_cursor.char_offset() - self.start_cursor.char_offset()
74 }
75
76 pub fn lines(&self) -> &'a str {
96 let start_index = match memrchr(b'\n', self.content_before().as_bytes()) {
97 Some(v) => v + 1,
98 None => 0,
99 };
100
101 let end_index = match memchr(b'\n', self.content_after().as_bytes()) {
102 Some(v) => v + self.end_cursor.byte_offset(),
103 None => self.content.len(),
104 };
105
106 &self.content[start_index..end_index]
107 }
108}
109
110#[cfg(test)]
115mod tests {
116 use super::*;
117
118 #[test]
119 fn test_lines_single_line() {
120 let text = "This\nis\nthe\ntest";
121 let span = Span::new(
122 text,
123 Cursor::new(1, 0, 0, 0), Cursor::new(1, 0, 0, 0), );
126
127 assert_eq!(span.lines(), "This", "The lines is incorrect");
128
129 let text = "This\nis\nthe\ntest";
131 let span = Span::new(
132 text,
133 Cursor::new(4, 0, 0, 0), Cursor::new(4, 0, 0, 0), );
136
137 assert_eq!(span.lines(), "This", "The lines is incorrect");
138
139 let text = "This\nis\nthe\ntest";
141 let span = Span::new(
142 text,
143 Cursor::new(5, 0, 0, 0), Cursor::new(5, 0, 0, 0), );
146
147 assert_eq!(span.lines(), "is", "The lines is incorrect");
148 }
149
150 #[test]
151 fn test_lines_multiline() {
152 let text = "This\nis\nthe\ntest";
153 let span = Span::new(
154 text,
155 Cursor::new(5, 0, 0, 0), Cursor::new(08, 0, 0, 0), );
158
159 assert_eq!(span.lines(), "is\nthe", "The lines is incorrect");
160 }
161}