saphyr-serde/parser/src/input.rs

127 lines
4.6 KiB
Rust
Raw Normal View History

/// Interface for a source of characters.
///
/// Hiding the input's implementation behind this trait allows mostly:
/// * For input-specific optimizations (for instance, using `str` methods instead of manually
/// transferring one `char` at a time to a buffer).
/// * To return `&str`s referencing the input string, thus avoiding potentially costly
/// allocations. Should users need an owned version of the data, they can always `.to_owned()`
/// their YAML object.
pub trait Input {
/// A hint to the input source that we will need to read `count` characters.
///
/// If the input is exhausted, `\0` can be used to pad the last characters and later returned.
/// The characters must not be consumed, but may be placed in an internal buffer.
///
/// This method may be a no-op if buffering yields no performance improvement.
///
/// Implementers of [`Input`] must _not_ load more than `count` characters into the buffer. The
/// parser tracks how many characters are loaded in the buffer and acts accordingly.
fn lookahead(&mut self, count: usize);
/// Return the number of buffered characters in `self`.
#[must_use]
fn buflen(&self) -> usize;
/// Return the capacity of the buffer in `self`.
#[must_use]
fn bufmaxlen(&self) -> usize;
/// Return whether the buffer (!= stream) is empty.
#[inline]
#[must_use]
fn buf_is_empty(&self) -> bool {
self.buflen() == 0
}
/// Read a character from the input stream and return it directly.
///
/// The internal buffer (is any) is bypassed.
#[must_use]
fn raw_read_ch(&mut self) -> char;
/// Put a character back in the buffer.
///
/// This function is only called when we read one too many characters and the pushed back
/// character is exactly the last character that was read. This function will not be called
/// multiple times consecutively.
fn push_back(&mut self, c: char);
/// Consume the next character.
fn skip(&mut self);
/// Consume the next `count` character.
fn skip_n(&mut self, count: usize);
/// Return the next character, without consuming it.
///
/// Users of the [`Input`] must make sure that the character has been loaded through a prior
/// call to [`Input::lookahead`]. Implementors of [`Input`] may assume that a valid call to
/// [`Input::lookahead`] has been made beforehand.
///
/// # Return
/// If the input source is not exhausted, returns the next character to be fed into the
/// scanner. Otherwise, returns `\0`.
#[must_use]
fn peek(&self) -> char;
/// Return the `n`-th character in the buffer, without consuming it.
///
/// This function assumes that the n-th character in the input has already been fetched through
/// [`Input::lookahead`].
#[must_use]
fn peek_nth(&self, n: usize) -> char;
/// Look for the next character and return it.
///
/// The character is not consumed.
/// Equivalent to calling [`Input::lookahead`] and [`Input::peek`].
#[inline]
#[must_use]
fn look_ch(&mut self) -> char {
self.lookahead(1);
self.peek()
}
/// Return whether the next character in the input source is equal to `c`.
///
/// This function assumes that the next character in the input has already been fetched through
/// [`Input::lookahead`].
#[inline]
#[must_use]
fn next_char_is(&self, c: char) -> bool {
self.peek() == c
}
/// Return whether the `n`-th character in the input source is equal to `c`.
///
/// This function assumes that the n-th character in the input has already been fetched through
/// [`Input::lookahead`].
#[inline]
#[must_use]
fn nth_char_is(&self, n: usize, c: char) -> bool {
self.peek_nth(n) == c
}
/// Return whether the next 2 characters in the input source match the given characters.
///
/// This function assumes that the next 2 characters in the input has already been fetched
/// through [`Input::lookahead`].
#[inline]
#[must_use]
fn next_2_are(&self, c1: char, c2: char) -> bool {
assert!(self.buflen() >= 2);
self.peek() == c1 && self.peek_nth(1) == c2
}
/// Return whether the next 3 characters in the input source match the given characters.
///
/// This function assumes that the next 3 characters in the input has already been fetched
/// through [`Input::lookahead`].
#[inline]
#[must_use]
fn next_3_are(&self, c1: char, c2: char, c3: char) -> bool {
assert!(self.buflen() >= 3);
self.peek() == c1 && self.peek_nth(1) == c2 && self.peek_nth(2) == c3
}
}