1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
use super::{ErrorKind, ParseDirection, ParseError, Parser};
use crate::string;
// Putting this impl in a submodule so that it appears before
// the integer parsing methods in the docs
impl<'a> Parser<'a> {
/// Constructs a Parser from a string.
///
/// This parser start with a `start_offset` of `0`,
/// [`with_start_offset`](Self::with_start_offset)
/// is preferable for parsing after the start of a string.
#[inline]
pub const fn new(string: &'a str) -> Self {
Self {
parse_direction: ParseDirection::FromStart,
start_offset: 0,
yielded_last_split: false,
str: string,
}
}
/// Constructs a Parser from `string` which is at `start_offset`
/// inside some other string.
///
/// # Example
///
/// ```rust
/// use konst::parsing::{ErrorKind, Parser};
///
/// // indices
/// // 0 4 8
/// // | | |
/// // "foo bar baz"
/// let substr = konst::string::str_from("foo bar baz", 4);
///
/// let parser = Parser::with_start_offset(substr, 4);
/// assert_eq!(parser.remainder(), "bar baz");
///
/// let (bar, parser) = parser.split(' ').unwrap();
/// assert_eq!(bar, "bar");
///
/// let err = parser.split_terminator(' ').unwrap_err();
///
/// assert_eq!(parser.remainder(), "baz");
/// assert_eq!(err.offset(), 8);
/// assert_eq!(err.kind(), ErrorKind::DelimiterNotFound);
///
/// ```
#[inline]
pub const fn with_start_offset(string: &'a str, start_offset: usize) -> Self {
Self {
parse_direction: ParseDirection::FromStart,
start_offset: start_offset as u32,
yielded_last_split: false,
str: string,
}
}
/// Skips `byte_count` bytes from the parsed string,
/// as well as however many bytes are required to be on a char boundary.
pub const fn skip(mut self, mut byte_count: usize) -> Self {
let bytes = self.str.as_bytes();
if byte_count > bytes.len() {
byte_count = bytes.len()
} else {
use konst_kernel::string::__is_char_boundary_bytes;
while !__is_char_boundary_bytes(bytes, byte_count) {
byte_count += 1;
}
};
self.parse_direction = ParseDirection::FromStart;
self.start_offset += byte_count as u32;
self.str = string::str_from(self.str, byte_count);
self
}
/// Skips `byte_count` bytes from the back of the parsed string,
/// as well as however many bytes are required to be on a char boundary.
pub const fn skip_back(mut self, byte_count: usize) -> Self {
use konst_kernel::string::__is_char_boundary_bytes;
let bytes = self.str.as_bytes();
let mut pos = self.str.len().saturating_sub(byte_count);
while !__is_char_boundary_bytes(bytes, pos) {
pos -= 1;
}
self.parse_direction = ParseDirection::FromEnd;
self.str = string::str_up_to(self.str, pos);
self
}
/// Returns the remaining, unparsed string.
#[inline(always)]
pub const fn remainder(self) -> &'a str {
self.str
}
/// Gets the byte offset of this parser in the str slice that this
/// was constructed from.
#[inline(always)]
pub const fn start_offset(self) -> usize {
self.start_offset as _
}
/// Gets the end byte offset of this parser in the str slice that this
/// was constructed from.
#[inline(always)]
pub const fn end_offset(self) -> usize {
self.start_offset as usize + self.str.len()
}
/// The direction that the parser was last mutated from.
pub const fn parse_direction(self) -> ParseDirection {
self.parse_direction
}
/// Constructs a [`ParseError`] for this point in parsing.
///
/// [`ParseError`]: struct.ParseError.html
pub const fn into_error(self, kind: ErrorKind) -> ParseError<'a> {
ParseError::new(self, kind)
}
/// Constructs a [`ParseError`] for this point in parsing,
/// for an [`ErrorKind::Other`] with a custom error message.
///
/// [`ParseError`]: struct.ParseError.html
/// [`ErrorKind::Other`]: ./enum.ErrorKind.html#variant.Other
pub const fn into_other_error(self, string: &'static &'static str) -> ParseError<'a> {
ParseError::other_error(self, string)
}
/// The amount of unparsed bytes.
#[inline(always)]
pub const fn len(self) -> usize {
self.str.len()
}
/// Whether there are any bytes left to parse.
#[inline(always)]
pub const fn is_empty(self) -> bool {
self.str.is_empty()
}
}