/*!
This crate provides an interface for regular expressions, with a focus on line
oriented search. The purpose of this crate is to provide a low level matching
interface that permits any kind of substring or regex implementation to power
the search routines provided by the
[`grep-searcher`](https://docs.rs/grep-searcher)
crate.
The primary thing provided by this crate is the
[`Matcher`](trait.Matcher.html)
trait. The trait defines an abstract interface for text search. It is robust
enough to support everything from basic substring search all the way to
arbitrarily complex regular expression implementations without sacrificing
performance.
A key design decision made in this crate is the use of *internal iteration*,
or otherwise known as the "push" model of searching. In this paradigm,
implementations of the `Matcher` trait will drive search and execute callbacks
provided by the caller when a match is found. This is in contrast to the
usual style of *external iteration* (the "pull" model) found throughout the
Rust ecosystem. There are two primary reasons why internal iteration was
chosen:
* Some search implementations may themselves require internal iteration.
Converting an internal iterator to an external iterator can be non-trivial
and sometimes even practically impossible.
* Rust's type system isn't quite expressive enough to write a generic interface
using external iteration without giving something else up (namely, ease of
use and/or performance).
In other words, internal iteration was chosen because it is the lowest common
denominator and because it is probably the least bad way of expressing the
interface in today's Rust. As a result, this trait isn't specifically intended
for everyday use, although, you might find it to be a happy price to pay if you
want to write code that is generic over multiple different regex
implementations.
*/
#![deny(missing_docs)]
extern crate memchr;
use std::fmt;
use std::io;
use std::ops;
use std::u64;
use interpolate::interpolate;
mod interpolate;
/// The type of a match.
///
/// The type of a match is a possibly empty range pointing to a contiguous
/// block of addressable memory.
///
/// Every `Match` is guaranteed to satisfy the invariant that `start <= end`.
///
/// # Indexing
///
/// This type is structurally identical to `std::ops::Range<usize>`, but
/// is a bit more ergonomic for dealing with match indices. In particular,
/// this type implements `Copy` and provides methods for building new `Match`
/// values based on old `Match` values. Finally, the invariant that `start`
/// is always less than or equal to `end` is enforced.
///
/// A `Match` can be used to slice a `&[u8]`, `&mut [u8]` or `&str` using
/// range notation. e.g.,
///
/// ```
/// use grep_matcher::Match;
///
/// let m = Match::new(2, 5);
/// let bytes = b"abcdefghi";
/// assert_eq!(b"cde", &bytes[m]);
/// ```
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Match {
start: usize,
end: usize,
}
impl Match {
/// Create a new match.
///
/// # Panics
///
/// This function panics if `start > end`.
#[inline]
pub fn new(start: usize, end: usize) -> Match {
assert!(start <= end);
Match { start, end }
}
/// Creates a zero width match at the given offset.
#[inline]
pub fn zero(offset: usize) -> Match {
Match { start: offset, end: offset }
}
/// Return the start offset of this match.
#[inline]
pub fn start(&self) -> usize {
self.start
}
/// Return the end offset of this match.
#[inline]
pub fn end(&self) -> usize {
self.end
}
/// Return a new match with the start offset replaced with the given
/// value.
///
/// # Panics
///
/// This method panics if `start > self.end`.
#[inline]
pub fn with_start(&self, start: usize) -> Match {
assert!(start <= self.end);
Match { start, ..*self }
}
/// Return a new match with the end offset replaced with the given
/// value.
///
/// # Panics
///
/// This method panics if `self.start > end`.
#[inline]
pub fn with_end(&self, end: usize) -> Match {
assert!(self.start <= end);
Match { end, ..*self }
}
/// Offset this match by the given amount and return a new match.
///
/// This adds the given offset to the start and end of this match, and
/// returns the resulting match.
///
/// # Panics
///
/// This panics if adding the given amount to either the start or end
/// offset would result in an overflow.
#[inline]
pub fn offset(&self, amount: usize) -> Match {
Match {
start: self.start.checked_add(amount).unwrap(),
end: self.end.checked_add(amount).unwrap(),
}
}
/// Returns the number of bytes in this match.
#[inline]
pub fn len(&self) -> usize {
self.end - self.start
}
/// Returns true if and only if this match is empty.
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl ops::Index<Match> for [u8] {
type Output = [u8];
#[inline]
fn<