peg_runtime/
str.rs

1//! Utilities for `str` input
2
3use super::{Parse, ParseElem, ParseLiteral, ParseSlice, RuleResult};
4use std::fmt::Display;
5
6/// Line and column within a string
7#[derive(PartialEq, Eq, Debug, Clone, Copy)]
8pub struct LineCol {
9    /// Line (1-indexed)
10    pub line: usize,
11
12    /// Column (1-indexed)
13    pub column: usize,
14
15    /// Byte offset from start of string (0-indexed)
16    pub offset: usize,
17}
18
19impl Display for LineCol {
20    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> {
21        write!(fmt, "{}:{}", self.line, self.column)
22    }
23}
24
25impl Parse for str {
26    type PositionRepr = LineCol;
27    #[inline]
28    fn start(&self) -> usize {
29        0
30    }
31
32    #[inline]
33    fn is_eof(&self, pos: usize) -> bool {
34        pos >= self.len()
35    }
36
37    fn position_repr(&self, pos: usize) -> LineCol {
38        let before = &self[..pos];
39        let line = before.as_bytes().iter().filter(|&&c| c == b'\n').count() + 1;
40        let column = before.chars().rev().take_while(|&c| c != '\n').count() + 1;
41        LineCol {
42            line,
43            column,
44            offset: pos,
45        }
46    }
47}
48
49impl<'input> ParseElem<'input> for str {
50    type Element = char;
51
52    #[inline]
53    fn parse_elem(&'input self, pos: usize) -> RuleResult<char> {
54        match self[pos..].chars().next() {
55            Some(c) => RuleResult::Matched(pos + c.len_utf8(), c),
56            None => RuleResult::Failed,
57        }
58    }
59}
60
61impl ParseLiteral for str {
62    #[inline]
63    fn parse_string_literal(&self, pos: usize, literal: &str) -> RuleResult<()> {
64        let l = literal.len();
65        if self.len() >= pos + l && &self.as_bytes()[pos..pos + l] == literal.as_bytes() {
66            RuleResult::Matched(pos + l, ())
67        } else {
68            RuleResult::Failed
69        }
70    }
71}
72
73impl<'input> ParseSlice<'input> for str {
74    type Slice = &'input str;
75    #[inline]
76    fn parse_slice(&'input self, p1: usize, p2: usize) -> &'input str {
77        &self[p1..p2]
78    }
79}