use memchr::{memchr, memrchr};
use crate::reader::Cursor;
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Span<'a> {
content: &'a str,
start_cursor: Cursor,
end_cursor: Cursor,
}
impl<'a> Span<'a> {
pub(in crate::reader) fn new(
content: &'a str,
start_cursor: Cursor,
end_cursor: Cursor,
) -> Span {
Span {
content,
start_cursor,
end_cursor,
}
}
pub fn whole_content(&self) -> &'a str {
self.content
}
pub fn content(&self) -> &'a str {
&self.content[self.start_cursor.byte_offset()..self.end_cursor.byte_offset()]
}
pub fn content_before(&self) -> &'a str {
&self.content[..self.start_cursor.byte_offset()]
}
pub fn content_after(&self) -> &'a str {
&self.content[self.end_cursor.byte_offset()..]
}
pub fn start_cursor(&self) -> &Cursor {
&self.start_cursor
}
pub fn end_cursor(&self) -> &Cursor {
&self.end_cursor
}
pub fn len(&self) -> usize {
self.end_cursor.byte_offset() - self.start_cursor.byte_offset()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn char_length(&self) -> usize {
self.end_cursor.char_offset() - self.start_cursor.char_offset()
}
pub fn lines(&self) -> &'a str {
let start_index = match memrchr(b'\n', self.content_before().as_bytes()) {
Some(v) => v + 1,
None => 0,
};
let end_index = match memchr(b'\n', self.content_after().as_bytes()) {
Some(v) => v + self.end_cursor.byte_offset(),
None => self.content.len(),
};
&self.content[start_index..end_index]
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_lines_single_line() {
let text = "This\nis\nthe\ntest";
let span = Span::new(
text,
Cursor::new(1, 0, 0, 0), Cursor::new(1, 0, 0, 0), );
assert_eq!(span.lines(), "This", "The lines is incorrect");
let text = "This\nis\nthe\ntest";
let span = Span::new(
text,
Cursor::new(4, 0, 0, 0), Cursor::new(4, 0, 0, 0), );
assert_eq!(span.lines(), "This", "The lines is incorrect");
let text = "This\nis\nthe\ntest";
let span = Span::new(
text,
Cursor::new(5, 0, 0, 0), Cursor::new(5, 0, 0, 0), );
assert_eq!(span.lines(), "is", "The lines is incorrect");
}
#[test]
fn test_lines_multiline() {
let text = "This\nis\nthe\ntest";
let span = Span::new(
text,
Cursor::new(5, 0, 0, 0), Cursor::new(08, 0, 0, 0), );
assert_eq!(span.lines(), "is\nthe", "The lines is incorrect");
}
}