string_sections/
line_span.rs

1use std::{
2    fmt,
3    ops::{Deref, Range},
4};
5
6use crate::str_to_range_unchecked;
7
8#[derive(PartialEq, Eq, Clone, Copy)]
9pub struct LineSpan<'a> {
10    pub(crate) text: &'a str,
11    pub start: usize,
12    pub end: usize,
13}
14
15impl<'a> LineSpan<'a> {
16    pub fn new(text: &'a str, substring: &str) -> Self {
17        let Range { start, end } = str_to_range_unchecked(text, substring);
18        LineSpan { text, start, end }
19    }
20
21    /// Returns the byte index range of the start and
22    /// end of the line, excluding the line ending
23    /// part `\n` or `\r\n`.
24    pub fn range(&self) -> Range<usize> {
25        self.start..self.end
26    }
27
28    /// Returns `&str` of the line, excluding `\n` and `\r\n`.
29    pub fn as_str(&self) -> &'a str {
30        &self.text[self.range()]
31    }
32}
33
34impl<'a> Deref for LineSpan<'a> {
35    type Target = str;
36
37    fn deref(&self) -> &Self::Target {
38        self.as_str()
39    }
40}
41
42impl<'a> From<LineSpan<'a>> for &'a str {
43    fn from(span: LineSpan<'a>) -> &'a str {
44        span.as_str()
45    }
46}
47
48impl<'a> From<LineSpan<'a>> for Range<usize> {
49    fn from(span: LineSpan<'a>) -> Range<usize> {
50        span.range()
51    }
52}
53
54impl<'a> fmt::Debug for LineSpan<'a> {
55    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
56        fmt.debug_struct("LineSpan")
57            .field("start", &self.start)
58            .field("end", &self.end)
59            .field("line", &self.as_str())
60            .finish()
61    }
62}
63
64impl<'a> fmt::Display for LineSpan<'a> {
65    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
66        self.as_str().fmt(fmt)
67    }
68}