Skip to main content

aho_corasick/util/
search.rs

1use core::ops::{Range, RangeBounds};
2
3use crate::util::primitives::PatternID;
4
5/// The configuration and the haystack to use for an Aho-Corasick search.
6///
7/// When executing a search, there are a few parameters one might want to
8/// configure:
9///
10/// * The haystack to search, provided to the [`Input::new`] constructor. This
11/// is the only required parameter.
12/// * The span _within_ the haystack to limit a search to. (The default
13/// is the entire haystack.) This is configured via [`Input::span`] or
14/// [`Input::range`].
15/// * Whether to run an unanchored (matches can occur anywhere after the
16/// start of the search) or anchored (matches can only occur beginning at
17/// the start of the search) search. Unanchored search is the default. This is
18/// configured via [`Input::anchored`].
19/// * Whether to quit the search as soon as a match has been found, regardless
20/// of the [`MatchKind`] that the searcher was built with. This is configured
21/// via [`Input::earliest`].
22///
23/// For most cases, the defaults for all optional parameters are appropriate.
24/// The utility of this type is that it keeps the default or common case simple
25/// while permitting tweaking parameters in more niche use cases while reusing
26/// the same search APIs.
27///
28/// # Valid bounds and search termination
29///
30/// An `Input` permits setting the bounds of a search via either
31/// [`Input::span`] or [`Input::range`]. The bounds set must be valid, or
32/// else a panic will occur. Bounds are valid if and only if:
33///
34/// * The bounds represent a valid range into the input's haystack.
35/// * **or** the end bound is a valid ending bound for the haystack *and*
36/// the start bound is exactly one greater than the end bound.
37///
38/// In the latter case, [`Input::is_done`] will return true and indicates any
39/// search receiving such an input should immediately return with no match.
40///
41/// Other than representing "search is complete," the `Input::span` and
42/// `Input::range` APIs are never necessary. Instead, callers can slice the
43/// haystack instead, e.g., with `&haystack[start..end]`. With that said, they
44/// can be more convenient than slicing because the match positions reported
45/// when using `Input::span` or `Input::range` are in terms of the original
46/// haystack. If you instead use `&haystack[start..end]`, then you'll need to
47/// add `start` to any match position returned in order for it to be a correct
48/// index into `haystack`.
49///
50/// # Example: `&str` and `&[u8]` automatically convert to an `Input`
51///
52/// There is a `From<&T> for Input` implementation for all `T: AsRef<[u8]>`.
53/// Additionally, the [`AhoCorasick`](crate::AhoCorasick) search APIs accept
54/// a `Into<Input>`. These two things combined together mean you can provide
55/// things like `&str` and `&[u8]` to search APIs when the defaults are
56/// suitable, but also an `Input` when they're not. For example:
57///
58/// ```
59/// use aho_corasick::{AhoCorasick, Anchored, Input, Match, StartKind};
60///
61/// // Build a searcher that supports both unanchored and anchored modes.
62/// let ac = AhoCorasick::builder()
63///     .start_kind(StartKind::Both)
64///     .build(&["abcd", "b"])
65///     .unwrap();
66/// let haystack = "abcd";
67///
68/// // A search using default parameters is unanchored. With standard
69/// // semantics, this finds `b` first.
70/// assert_eq!(
71///     Some(Match::must(1, 1..2)),
72///     ac.find(haystack),
73/// );
74/// // Using the same 'find' routine, we can provide an 'Input' explicitly
75/// // that is configured to do an anchored search. Since 'b' doesn't start
76/// // at the beginning of the search, it is not reported as a match.
77/// assert_eq!(
78///     Some(Match::must(0, 0..4)),
79///     ac.find(Input::new(haystack).anchored(Anchored::Yes)),
80/// );
81/// ```
82#[derive(Clone)]
83pub struct Input<'h> {
84    haystack: &'h [u8],
85    span: Span,
86    anchored: Anchored,
87    earliest: bool,
88}
89
90impl<'h> Input<'h> {
91    /// Create a new search configuration for the given haystack.
92    #[inline]
93    pub fn new<H: ?Sized + AsRef<[u8]>>(haystack: &'h H) -> Input<'h> {
94        Input {
95            haystack: haystack.as_ref(),
96            span: Span { start: 0, end: haystack.as_ref().len() },
97            anchored: Anchored::No,
98            earliest: false,
99        }
100    }
101
102    /// Set the span for this search.
103    ///
104    /// This routine is generic over how a span is provided. While
105    /// a [`Span`] may be given directly, one may also provide a
106    /// `std::ops::Range<usize>`. To provide anything supported by range
107    /// syntax, use the [`Input::range`] method.
108    ///
109    /// The default span is the entire haystack.
110    ///
111    /// Note that [`Input::range`] overrides this method and vice versa.
112    ///
113    /// # Panics
114    ///
115    /// This panics if the given span does not correspond to valid bounds in
116    /// the haystack or the termination of a search.
117    ///
118    /// # Example
119    ///
120    /// This example shows how the span of the search can impact whether a
121    /// match is reported or not.
122    ///
123    /// ```
124    /// use aho_corasick::{AhoCorasick, Input, MatchKind};
125    ///
126    /// let patterns = &["b", "abcd", "abc"];
127    /// let haystack = "abcd";
128    ///
129    /// let ac = AhoCorasick::builder()
130    ///     .match_kind(MatchKind::LeftmostFirst)
131    ///     .build(patterns)
132    ///     .unwrap();
133    /// let input = Input::new(haystack).span(0..3);
134    /// let mat = ac.try_find(input)?.expect("should have a match");
135    /// // Without the span stopping the search early, 'abcd' would be reported
136    /// // because it is the correct leftmost-first match.
137    /// assert_eq!("abc", &haystack[mat.span()]);
138    ///
139    /// # Ok::<(), Box<dyn std::error::Error>>(())
140    /// ```
141    #[inline]
142    pub fn span<S: Into<Span>>(mut self, span: S) -> Input<'h> {
143        self.set_span(span);
144        self
145    }
146
147    /// Like `Input::span`, but accepts any range instead.
148    ///
149    /// The default range is the entire haystack.
150    ///
151    /// Note that [`Input::span`] overrides this method and vice versa.
152    ///
153    /// # Panics
154    ///
155    /// This routine will panic if the given range could not be converted
156    /// to a valid [`Range`]. For example, this would panic when given
157    /// `0..=usize::MAX` since it cannot be represented using a half-open
158    /// interval in terms of `usize`.
159    ///
160    /// This routine also panics if the given range does not correspond to
161    /// valid bounds in the haystack or the termination of a search.
162    ///
163    /// # Example
164    ///
165    /// ```
166    /// use aho_corasick::Input;
167    ///
168    /// let input = Input::new("foobar");
169    /// assert_eq!(0..6, input.get_range());
170    ///
171    /// let input = Input::new("foobar").range(2..=4);
172    /// assert_eq!(2..5, input.get_range());
173    /// ```
174    #[inline]
175    pub fn range<R: RangeBounds<usize>>(mut self, range: R) -> Input<'h> {
176        self.set_range(range);
177        self
178    }
179
180    /// Sets the anchor mode of a search.
181    ///
182    /// When a search is anchored (via [`Anchored::Yes`]), a match must begin
183    /// at the start of a search. When a search is not anchored (that's
184    /// [`Anchored::No`]), searchers will look for a match anywhere in the
185    /// haystack.
186    ///
187    /// By default, the anchored mode is [`Anchored::No`].
188    ///
189    /// # Support for anchored searches
190    ///
191    /// Anchored or unanchored searches might not always be available,
192    /// depending on the type of searcher used and its configuration:
193    ///
194    /// * [`noncontiguous::NFA`](crate::nfa::noncontiguous::NFA) always
195    /// supports both unanchored and anchored searches.
196    /// * [`contiguous::NFA`](crate::nfa::contiguous::NFA) always supports both
197    /// unanchored and anchored searches.
198    /// * [`dfa::DFA`](crate::dfa::DFA) supports only unanchored
199    /// searches by default.
200    /// [`dfa::Builder::start_kind`](crate::dfa::Builder::start_kind) can
201    /// be used to change the default to supporting both kinds of searches
202    /// or even just anchored searches.
203    /// * [`AhoCorasick`](crate::AhoCorasick) inherits the same setup as a
204    /// `DFA`. Namely, it only supports unanchored searches by default, but
205    /// [`AhoCorasickBuilder::start_kind`](crate::AhoCorasickBuilder::start_kind)
206    /// can change this.
207    ///
208    /// If you try to execute a search using a `try_` ("fallible") method with
209    /// an unsupported anchor mode, then an error will be returned. For calls
210    /// to infallible search methods, a panic will result.
211    ///
212    /// # Example
213    ///
214    /// This demonstrates the differences between an anchored search and
215    /// an unanchored search. Notice that we build our `AhoCorasick` searcher
216    /// with [`StartKind::Both`] so that it supports both unanchored and
217    /// anchored searches simultaneously.
218    ///
219    /// ```
220    /// use aho_corasick::{
221    ///     AhoCorasick, Anchored, Input, MatchKind, StartKind,
222    /// };
223    ///
224    /// let patterns = &["bcd"];
225    /// let haystack = "abcd";
226    ///
227    /// let ac = AhoCorasick::builder()
228    ///     .start_kind(StartKind::Both)
229    ///     .build(patterns)
230    ///     .unwrap();
231    ///
232    /// // Note that 'Anchored::No' is the default, so it doesn't need to
233    /// // be explicitly specified here.
234    /// let input = Input::new(haystack);
235    /// let mat = ac.try_find(input)?.expect("should have a match");
236    /// assert_eq!("bcd", &haystack[mat.span()]);
237    ///
238    /// // While 'bcd' occurs in the haystack, it does not begin where our
239    /// // search begins, so no match is found.
240    /// let input = Input::new(haystack).anchored(Anchored::Yes);
241    /// assert_eq!(None, ac.try_find(input)?);
242    ///
243    /// // However, if we start our search where 'bcd' starts, then we will
244    /// // find a match.
245    /// let input = Input::new(haystack).range(1..).anchored(Anchored::Yes);
246    /// let mat = ac.try_find(input)?.expect("should have a match");
247    /// assert_eq!("bcd", &haystack[mat.span()]);
248    ///
249    /// # Ok::<(), Box<dyn std::error::Error>>(())
250    /// ```
251    #[inline]
252    pub fn anchored(mut self, mode: Anchored) -> Input<'h> {
253        self.set_anchored(mode);
254        self
255    }
256
257    /// Whether to execute an "earliest" search or not.
258    ///
259    /// When running a non-overlapping search, an "earliest" search will
260    /// return the match location as early as possible. For example, given
261    /// the patterns `abc` and `b`, and a haystack of `abc`, a normal
262    /// leftmost-first search will return `abc` as a match. But an "earliest"
263    /// search will return as soon as it is known that a match occurs, which
264    /// happens once `b` is seen.
265    ///
266    /// Note that when using [`MatchKind::Standard`], the "earliest" option
267    /// has no effect since standard semantics are already "earliest." Note
268    /// also that this has no effect in overlapping searches, since overlapping
269    /// searches also use standard semantics and report all possible matches.
270    ///
271    /// This is disabled by default.
272    ///
273    /// # Example
274    ///
275    /// This example shows the difference between "earliest" searching and
276    /// normal leftmost searching.
277    ///
278    /// ```
279    /// use aho_corasick::{AhoCorasick, Anchored, Input, MatchKind, StartKind};
280    ///
281    /// let patterns = &["abc", "b"];
282    /// let haystack = "abc";
283    ///
284    /// let ac = AhoCorasick::builder()
285    ///     .match_kind(MatchKind::LeftmostFirst)
286    ///     .build(patterns)
287    ///     .unwrap();
288    ///
289    /// // The normal leftmost-first match.
290    /// let input = Input::new(haystack);
291    /// let mat = ac.try_find(input)?.expect("should have a match");
292    /// assert_eq!("abc", &haystack[mat.span()]);
293    ///
294    /// // The "earliest" possible match, even if it isn't leftmost-first.
295    /// let input = Input::new(haystack).earliest(true);
296    /// let mat = ac.try_find(input)?.expect("should have a match");
297    /// assert_eq!("b", &haystack[mat.span()]);
298    ///
299    /// # Ok::<(), Box<dyn std::error::Error>>(())
300    /// ```
301    #[inline]
302    pub fn earliest(mut self, yes: bool) -> Input<'h> {
303        self.set_earliest(yes);
304        self
305    }
306
307    /// Set the span for this search configuration.
308    ///
309    /// This is like the [`Input::span`] method, except this mutates the
310    /// span in place.
311    ///
312    /// This routine is generic over how a span is provided. While
313    /// a [`Span`] may be given directly, one may also provide a
314    /// `std::ops::Range<usize>`.
315    ///
316    /// # Panics
317    ///
318    /// This panics if the given span does not correspond to valid bounds in
319    /// the haystack or the termination of a search.
320    ///
321    /// # Example
322    ///
323    /// ```
324    /// use aho_corasick::Input;
325    ///
326    /// let mut input = Input::new("foobar");
327    /// assert_eq!(0..6, input.get_range());
328    /// input.set_span(2..4);
329    /// assert_eq!(2..4, input.get_range());
330    /// ```
331    #[inline]
332    pub fn set_span<S: Into<Span>>(&mut self, span: S) {
333        let span = span.into();
334        assert!(
335            span.end <= self.haystack.len()
336                && span.start <= span.end.wrapping_add(1),
337            "invalid span {:?} for haystack of length {}",
338            span,
339            self.haystack.len(),
340        );
341        self.span = span;
342    }
343
344    /// Set the span for this search configuration given any range.
345    ///
346    /// This is like the [`Input::range`] method, except this mutates the
347    /// span in place.
348    ///
349    /// # Panics
350    ///
351    /// This routine will panic if the given range could not be converted
352    /// to a valid [`Range`]. For example, this would panic when given
353    /// `0..=usize::MAX` since it cannot be represented using a half-open
354    /// interval in terms of `usize`.
355    ///
356    /// This routine also panics if the given range does not correspond to
357    /// valid bounds in the haystack or the termination of a search.
358    ///
359    /// # Example
360    ///
361    /// ```
362    /// use aho_corasick::Input;
363    ///
364    /// let mut input = Input::new("foobar");
365    /// assert_eq!(0..6, input.get_range());
366    /// input.set_range(2..=4);
367    /// assert_eq!(2..5, input.get_range());
368    /// ```
369    #[inline]
370    pub fn set_range<R: RangeBounds<usize>>(&mut self, range: R) {
371        use core::ops::Bound;
372
373        // It's a little weird to convert ranges into spans, and then spans
374        // back into ranges when we actually slice the haystack. Because
375        // of that process, we always represent everything as a half-open
376        // internal. Therefore, handling things like m..=n is a little awkward.
377        let start = match range.start_bound() {
378            Bound::Included(&i) => i,
379            // Can this case ever happen? Range syntax doesn't support it...
380            Bound::Excluded(&i) => i.checked_add(1).unwrap(),
381            Bound::Unbounded => 0,
382        };
383        let end = match range.end_bound() {
384            Bound::Included(&i) => i.checked_add(1).unwrap(),
385            Bound::Excluded(&i) => i,
386            Bound::Unbounded => self.haystack().len(),
387        };
388        self.set_span(Span { start, end });
389    }
390
391    /// Set the starting offset for the span for this search configuration.
392    ///
393    /// This is a convenience routine for only mutating the start of a span
394    /// without having to set the entire span.
395    ///
396    /// # Panics
397    ///
398    /// This panics if the given span does not correspond to valid bounds in
399    /// the haystack or the termination of a search.
400    ///
401    /// # Example
402    ///
403    /// ```
404    /// use aho_corasick::Input;
405    ///
406    /// let mut input = Input::new("foobar");
407    /// assert_eq!(0..6, input.get_range());
408    /// input.set_start(5);
409    /// assert_eq!(5..6, input.get_range());
410    /// ```
411    #[inline]
412    pub fn set_start(&mut self, start: usize) {
413        self.set_span(Span { start, ..self.get_span() });
414    }
415
416    /// Set the ending offset for the span for this search configuration.
417    ///
418    /// This is a convenience routine for only mutating the end of a span
419    /// without having to set the entire span.
420    ///
421    /// # Panics
422    ///
423    /// This panics if the given span does not correspond to valid bounds in
424    /// the haystack or the termination of a search.
425    ///
426    /// # Example
427    ///
428    /// ```
429    /// use aho_corasick::Input;
430    ///
431    /// let mut input = Input::new("foobar");
432    /// assert_eq!(0..6, input.get_range());
433    /// input.set_end(5);
434    /// assert_eq!(0..5, input.get_range());
435    /// ```
436    #[inline]
437    pub fn set_end(&mut self, end: usize) {
438        self.set_span(Span { end, ..self.get_span() });
439    }
440
441    /// Set the anchor mode of a search.
442    ///
443    /// This is like [`Input::anchored`], except it mutates the search
444    /// configuration in place.
445    ///
446    /// # Example
447    ///
448    /// ```
449    /// use aho_corasick::{Anchored, Input};
450    ///
451    /// let mut input = Input::new("foobar");
452    /// assert_eq!(Anchored::No, input.get_anchored());
453    ///
454    /// input.set_anchored(Anchored::Yes);
455    /// assert_eq!(Anchored::Yes, input.get_anchored());
456    /// ```
457    #[inline]
458    pub fn set_anchored(&mut self, mode: Anchored) {
459        self.anchored = mode;
460    }
461
462    /// Set whether the search should execute in "earliest" mode or not.
463    ///
464    /// This is like [`Input::earliest`], except it mutates the search
465    /// configuration in place.
466    ///
467    /// # Example
468    ///
469    /// ```
470    /// use aho_corasick::Input;
471    ///
472    /// let mut input = Input::new("foobar");
473    /// assert!(!input.get_earliest());
474    /// input.set_earliest(true);
475    /// assert!(input.get_earliest());
476    /// ```
477    #[inline]
478    pub fn set_earliest(&mut self, yes: bool) {
479        self.earliest = yes;
480    }
481
482    /// Return a borrow of the underlying haystack as a slice of bytes.
483    ///
484    /// # Example
485    ///
486    /// ```
487    /// use aho_corasick::Input;
488    ///
489    /// let input = Input::new("foobar");
490    /// assert_eq!(b"foobar", input.haystack());
491    /// ```
492    #[inline]
493    pub fn haystack(&self) -> &[u8] {
494        self.haystack
495    }
496
497    /// Return the start position of this search.
498    ///
499    /// This is a convenience routine for `search.get_span().start()`.
500    ///
501    /// # Example
502    ///
503    /// ```
504    /// use aho_corasick::Input;
505    ///
506    /// let input = Input::new("foobar");
507    /// assert_eq!(0, input.start());
508    ///
509    /// let input = Input::new("foobar").span(2..4);
510    /// assert_eq!(2, input.start());
511    /// ```
512    #[inline]
513    pub fn start(&self) -> usize {
514        self.get_span().start
515    }
516
517    /// Return the end position of this search.
518    ///
519    /// This is a convenience routine for `search.get_span().end()`.
520    ///
521    /// # Example
522    ///
523    /// ```
524    /// use aho_corasick::Input;
525    ///
526    /// let input = Input::new("foobar");
527    /// assert_eq!(6, input.end());
528    ///
529    /// let input = Input::new("foobar").span(2..4);
530    /// assert_eq!(4, input.end());
531    /// ```
532    #[inline]
533    pub fn end(&self) -> usize {
534        self.get_span().end
535    }
536
537    /// Return the span for this search configuration.
538    ///
539    /// If one was not explicitly set, then the span corresponds to the entire
540    /// range of the haystack.
541    ///
542    /// # Example
543    ///
544    /// ```
545    /// use aho_corasick::{Input, Span};
546    ///
547    /// let input = Input::new("foobar");
548    /// assert_eq!(Span { start: 0, end: 6 }, input.get_span());
549    /// ```
550    #[inline]
551    pub fn get_span(&self) -> Span {
552        self.span
553    }
554
555    /// Return the span as a range for this search configuration.
556    ///
557    /// If one was not explicitly set, then the span corresponds to the entire
558    /// range of the haystack.
559    ///
560    /// # Example
561    ///
562    /// ```
563    /// use aho_corasick::Input;
564    ///
565    /// let input = Input::new("foobar");
566    /// assert_eq!(0..6, input.get_range());
567    /// ```
568    #[inline]
569    pub fn get_range(&self) -> Range<usize> {
570        self.get_span().range()
571    }
572
573    /// Return the anchored mode for this search configuration.
574    ///
575    /// If no anchored mode was set, then it defaults to [`Anchored::No`].
576    ///
577    /// # Example
578    ///
579    /// ```
580    /// use aho_corasick::{Anchored, Input};
581    ///
582    /// let mut input = Input::new("foobar");
583    /// assert_eq!(Anchored::No, input.get_anchored());
584    ///
585    /// input.set_anchored(Anchored::Yes);
586    /// assert_eq!(Anchored::Yes, input.get_anchored());
587    /// ```
588    #[inline]
589    pub fn get_anchored(&self) -> Anchored {
590        self.anchored
591    }
592
593    /// Return whether this search should execute in "earliest" mode.
594    ///
595    /// # Example
596    ///
597    /// ```
598    /// use aho_corasick::Input;
599    ///
600    /// let input = Input::new("foobar");
601    /// assert!(!input.get_earliest());
602    /// ```
603    #[inline]
604    pub fn get_earliest(&self) -> bool {
605        self.earliest
606    }
607
608    /// Return true if this input has been exhausted, which in turn means all
609    /// subsequent searches will return no matches.
610    ///
611    /// This occurs precisely when the start position of this search is greater
612    /// than the end position of the search.
613    ///
614    /// # Example
615    ///
616    /// ```
617    /// use aho_corasick::Input;
618    ///
619    /// let mut input = Input::new("foobar");
620    /// assert!(!input.is_done());
621    /// input.set_start(6);
622    /// assert!(!input.is_done());
623    /// input.set_start(7);
624    /// assert!(input.is_done());
625    /// ```
626    #[inline]
627    pub fn is_done(&self) -> bool {
628        self.get_span().start > self.get_span().end
629    }
630}
631
632impl<'h> core::fmt::Debug for Input<'h> {
633    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
634        let mut fmter = f.debug_struct("Input");
635        match core::str::from_utf8(self.haystack()) {
636            Ok(nice) => fmter.field("haystack", &nice),
637            Err(_) => fmter.field("haystack", &self.haystack()),
638        }
639        .field("span", &self.span)
640        .field("anchored", &self.anchored)
641        .field("earliest", &self.earliest)
642        .finish()
643    }
644}
645
646impl<'h, H: ?Sized + AsRef<[u8]>> From<&'h H> for Input<'h> {
647    #[inline]
648    fn from(haystack: &'h H) -> Input<'h> {
649        Input::new(haystack)
650    }
651}
652
653/// A representation of a range in a haystack.
654///
655/// A span corresponds to the starting and ending _byte offsets_ of a
656/// contiguous region of bytes. The starting offset is inclusive while the
657/// ending offset is exclusive. That is, a span is a half-open interval.
658///
659/// A span is used to report the offsets of a match, but it is also used to
660/// convey which region of a haystack should be searched via routines like
661/// [`Input::span`].
662///
663/// This is basically equivalent to a `std::ops::Range<usize>`, except this
664/// type implements `Copy` which makes it more ergonomic to use in the context
665/// of this crate. Indeed, `Span` exists only because `Range<usize>` does
666/// not implement `Copy`. Like a range, this implements `Index` for `[u8]`
667/// and `str`, and `IndexMut` for `[u8]`. For convenience, this also impls
668/// `From<Range>`, which means things like `Span::from(5..10)` work.
669///
670/// There are no constraints on the values of a span. It is, for example, legal
671/// to create a span where `start > end`.
672#[derive(Clone, Copy, Eq, Hash, PartialEq)]
673pub struct Span {
674    /// The start offset of the span, inclusive.
675    pub start: usize,
676    /// The end offset of the span, exclusive.
677    pub end: usize,
678}
679
680impl Span {
681    /// Returns this span as a range.
682    #[inline]
683    pub fn range(&self) -> Range<usize> {
684        Range::from(*self)
685    }
686
687    /// Returns true when this span is empty. That is, when `start >= end`.
688    #[inline]
689    pub fn is_empty(&self) -> bool {
690        self.start >= self.end
691    }
692
693    /// Returns the length of this span.
694    ///
695    /// This returns `0` in precisely the cases that `is_empty` returns `true`.
696    #[inline]
697    pub fn len(&self) -> usize {
698        self.end.saturating_sub(self.start)
699    }
700
701    /// Returns true when the given offset is contained within this span.
702    ///
703    /// Note that an empty span contains no offsets and will always return
704    /// false.
705    #[inline]
706    pub fn contains(&self, offset: usize) -> bool {
707        !self.is_empty() && self.start <= offset && offset <= self.end
708    }
709
710    /// Returns a new span with `offset` added to this span's `start` and `end`
711    /// values.
712    ///
713    /// # Panics
714    ///
715    /// This panics if adding `offset` to either part of this `Span` would
716    /// result in overflow.
717    #[inline]
718    pub fn offset(&self, offset: usize) -> Span {
719        Span {
720            start: self
721                .start
722                .checked_add(offset)
723                .expect("invalid start+offset"),
724            end: self.end.checked_add(offset).expect("invalid end+offset"),
725        }
726    }
727}
728
729impl core::fmt::Debug for Span {
730    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
731        write!(f, "{}..{}", self.start, self.end)
732    }
733}
734
735impl core::ops::Index<Span> for [u8] {
736    type Output = [u8];
737
738    #[inline]
739    fn index(&self, index: Span) -> &[u8] {
740        &self[index.range()]
741    }
742}
743
744impl core::ops::IndexMut<Span> for [u8] {
745    #[inline]
746    fn index_mut(&mut self, index: Span) -> &mut [u8] {
747        &mut self[index.range()]
748    }
749}
750
751impl core::ops::Index<Span> for str {
752    type Output = str;
753
754    #[inline]
755    fn index(&self, index: Span) -> &str {
756        &self[index.range()]
757    }
758}
759
760impl From<Range<usize>> for Span {
761    #[inline]
762    fn from(range: Range<usize>) -> Span {
763        Span { start: range.start, end: range.end }
764    }
765}
766
767impl From<Span> for Range<usize> {
768    #[inline]
769    fn from(span: Span) -> Range<usize> {
770        Range { start: span.start, end: span.end }
771    }
772}
773
774impl PartialEq<Range<usize>> for Span {
775    #[inline]
776    fn eq(&self, range: &Range<usize>) -> bool {
777        self.start == range.start && self.end == range.end
778    }
779}
780
781impl PartialEq<Span> for Range<usize> {
782    #[inline]
783    fn eq(&self, span: &Span) -> bool {
784        self.start == span.start && self.end == span.end
785    }
786}
787
788/// The type of anchored search to perform.
789///
790/// If an Aho-Corasick searcher does not support the anchored mode selected,
791/// then the search will return an error or panic, depending on whether a
792/// fallible or an infallible routine was called.
793#[non_exhaustive]
794#[derive(Clone, Copy, Debug, Eq, PartialEq)]
795pub enum Anchored {
796    /// Run an unanchored search. This means a match may occur anywhere at or
797    /// after the start position of the search up until the end position of the
798    /// search.
799    No,
800    /// Run an anchored search. This means that a match must begin at the start
801    /// position of the search and end before the end position of the search.
802    Yes,
803}
804
805impl Anchored {
806    /// Returns true if and only if this anchor mode corresponds to an anchored
807    /// search.
808    ///
809    /// # Example
810    ///
811    /// ```
812    /// use aho_corasick::Anchored;
813    ///
814    /// assert!(!Anchored::No.is_anchored());
815    /// assert!(Anchored::Yes.is_anchored());
816    /// ```
817    #[inline]
818    pub fn is_anchored(&self) -> bool {
819        matches!(*self, Anchored::Yes)
820    }
821}
822
823/// A representation of a match reported by an Aho-Corasick searcher.
824///
825/// A match has two essential pieces of information: the [`PatternID`] that
826/// matches, and the [`Span`] of the match in a haystack.
827///
828/// The pattern is identified by an ID, which corresponds to its position
829/// (starting from `0`) relative to other patterns used to construct the
830/// corresponding searcher. If only a single pattern is provided, then all
831/// matches are guaranteed to have a pattern ID of `0`.
832///
833/// Every match reported by a searcher guarantees that its span has its start
834/// offset as less than or equal to its end offset.
835#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
836pub struct Match {
837    /// The pattern ID.
838    pattern: PatternID,
839    /// The underlying match span.
840    span: Span,
841}
842
843impl Match {
844    /// Create a new match from a pattern ID and a span.
845    ///
846    /// This constructor is generic over how a span is provided. While
847    /// a [`Span`] may be given directly, one may also provide a
848    /// `std::ops::Range<usize>`.
849    ///
850    /// # Panics
851    ///
852    /// This panics if `end < start`.
853    ///
854    /// # Example
855    ///
856    /// This shows how to create a match for the first pattern in an
857    /// Aho-Corasick searcher using convenient range syntax.
858    ///
859    /// ```
860    /// use aho_corasick::{Match, PatternID};
861    ///
862    /// let m = Match::new(PatternID::ZERO, 5..10);
863    /// assert_eq!(0, m.pattern().as_usize());
864    /// assert_eq!(5, m.start());
865    /// assert_eq!(10, m.end());
866    /// ```
867    #[inline]
868    pub fn new<S: Into<Span>>(pattern: PatternID, span: S) -> Match {
869        let span = span.into();
870        assert!(span.start <= span.end, "invalid match span");
871        Match { pattern, span }
872    }
873
874    /// Create a new match from a pattern ID and a byte offset span.
875    ///
876    /// This constructor is generic over how a span is provided. While
877    /// a [`Span`] may be given directly, one may also provide a
878    /// `std::ops::Range<usize>`.
879    ///
880    /// This is like [`Match::new`], but accepts a `usize` instead of a
881    /// [`PatternID`]. This panics if the given `usize` is not representable
882    /// as a `PatternID`.
883    ///
884    /// # Panics
885    ///
886    /// This panics if `end < start` or if `pattern > PatternID::MAX`.
887    ///
888    /// # Example
889    ///
890    /// This shows how to create a match for the third pattern in an
891    /// Aho-Corasick searcher using convenient range syntax.
892    ///
893    /// ```
894    /// use aho_corasick::Match;
895    ///
896    /// let m = Match::must(3, 5..10);
897    /// assert_eq!(3, m.pattern().as_usize());
898    /// assert_eq!(5, m.start());
899    /// assert_eq!(10, m.end());
900    /// ```
901    #[inline]
902    pub fn must<S: Into<Span>>(pattern: usize, span: S) -> Match {
903        Match::new(PatternID::must(pattern), span)
904    }
905
906    /// Returns the ID of the pattern that matched.
907    ///
908    /// The ID of a pattern is derived from the position in which it was
909    /// originally inserted into the corresponding searcher. The first pattern
910    /// has identifier `0`, and each subsequent pattern is `1`, `2` and so on.
911    #[inline]
912    pub fn pattern(&self) -> PatternID {
913        self.pattern
914    }
915
916    /// The starting position of the match.
917    ///
918    /// This is a convenience routine for `Match::span().start`.
919    #[inline]
920    pub fn start(&self) -> usize {
921        self.span().start
922    }
923
924    /// The ending position of the match.
925    ///
926    /// This is a convenience routine for `Match::span().end`.
927    #[inline]
928    pub fn end(&self) -> usize {
929        self.span().end
930    }
931
932    /// Returns the match span as a range.
933    ///
934    /// This is a convenience routine for `Match::span().range()`.
935    #[inline]
936    pub fn range(&self) -> core::ops::Range<usize> {
937        self.span().range()
938    }
939
940    /// Returns the span for this match.
941    #[inline]
942    pub fn span(&self) -> Span {
943        self.span
944    }
945
946    /// Returns true when the span in this match is empty.
947    ///
948    /// An empty match can only be returned when empty pattern is in the
949    /// Aho-Corasick searcher.
950    #[inline]
951    pub fn is_empty(&self) -> bool {
952        self.span().is_empty()
953    }
954
955    /// Returns the length of this match.
956    ///
957    /// This returns `0` in precisely the cases that `is_empty` returns `true`.
958    #[inline]
959    pub fn len(&self) -> usize {
960        self.span().len()
961    }
962
963    /// Returns a new match with `offset` added to its span's `start` and `end`
964    /// values.
965    ///
966    /// # Panics
967    ///
968    /// This panics if adding `offset` to either part of this match's `Span`
969    /// would result in overflow.
970    #[inline]
971    pub fn offset(&self, offset: usize) -> Match {
972        Match { pattern: self.pattern, span: self.span.offset(offset) }
973    }
974}
975
976/// A knob for controlling the match semantics of an Aho-Corasick automaton.
977///
978/// There are two generally different ways that Aho-Corasick automatons can
979/// report matches. The first way is the "standard" approach that results from
980/// implementing most textbook explanations of Aho-Corasick. The second way is
981/// to report only the leftmost non-overlapping matches. The leftmost approach
982/// is in turn split into two different ways of resolving ambiguous matches:
983/// leftmost-first and leftmost-longest.
984///
985/// The `Standard` match kind is the default and is the only one that supports
986/// overlapping matches and stream searching. (Trying to find overlapping or
987/// streaming matches using leftmost match semantics will result in an error in
988/// fallible APIs and a panic when using infallibe APIs.) The `Standard` match
989/// kind will report matches as they are seen. When searching for overlapping
990/// matches, then all possible matches are reported. When searching for
991/// non-overlapping matches, the first match seen is reported. For example, for
992/// non-overlapping matches, given the patterns `abcd` and `b` and the haystack
993/// `abcdef`, only a match for `b` is reported since it is detected first. The
994/// `abcd` match is never reported since it overlaps with the `b` match.
995///
996/// In contrast, the leftmost match kind always prefers the leftmost match
997/// among all possible matches. Given the same example as above with `abcd` and
998/// `b` as patterns and `abcdef` as the haystack, the leftmost match is `abcd`
999/// since it begins before the `b` match, even though the `b` match is detected
1000/// before the `abcd` match. In this case, the `b` match is not reported at all
1001/// since it overlaps with the `abcd` match.
1002///
1003/// The difference between leftmost-first and leftmost-longest is in how they
1004/// resolve ambiguous matches when there are multiple leftmost matches to
1005/// choose from. Leftmost-first always chooses the pattern that was provided
1006/// earliest, where as leftmost-longest always chooses the longest matching
1007/// pattern. For example, given the patterns `a` and `ab` and the subject
1008/// string `ab`, the leftmost-first match is `a` but the leftmost-longest match
1009/// is `ab`. Conversely, if the patterns were given in reverse order, i.e.,
1010/// `ab` and `a`, then both the leftmost-first and leftmost-longest matches
1011/// would be `ab`. Stated differently, the leftmost-first match depends on the
1012/// order in which the patterns were given to the Aho-Corasick automaton.
1013/// Because of that, when leftmost-first matching is used, if a pattern `A`
1014/// that appears before a pattern `B` is a prefix of `B`, then it is impossible
1015/// to ever observe a match of `B`.
1016///
1017/// If you're not sure which match kind to pick, then stick with the standard
1018/// kind, which is the default. In particular, if you need overlapping or
1019/// streaming matches, then you _must_ use the standard kind. The leftmost
1020/// kinds are useful in specific circumstances. For example, leftmost-first can
1021/// be very useful as a way to implement match priority based on the order of
1022/// patterns given and leftmost-longest can be useful for dictionary searching
1023/// such that only the longest matching words are reported.
1024///
1025/// # Relationship with regular expression alternations
1026///
1027/// Understanding match semantics can be a little tricky, and one easy way
1028/// to conceptualize non-overlapping matches from an Aho-Corasick automaton
1029/// is to think about them as a simple alternation of literals in a regular
1030/// expression. For example, let's say we wanted to match the strings
1031/// `Sam` and `Samwise`, which would turn into the regex `Sam|Samwise`. It
1032/// turns out that regular expression engines have two different ways of
1033/// matching this alternation. The first way, leftmost-longest, is commonly
1034/// found in POSIX compatible implementations of regular expressions (such as
1035/// `grep`). The second way, leftmost-first, is commonly found in backtracking
1036/// implementations such as Perl. (Some regex engines, such as RE2 and Rust's
1037/// regex engine do not use backtracking, but still implement leftmost-first
1038/// semantics in an effort to match the behavior of dominant backtracking
1039/// regex engines such as those found in Perl, Ruby, Python, Javascript and
1040/// PHP.)
1041///
1042/// That is, when matching `Sam|Samwise` against `Samwise`, a POSIX regex
1043/// will match `Samwise` because it is the longest possible match, but a
1044/// Perl-like regex will match `Sam` since it appears earlier in the
1045/// alternation. Indeed, the regex `Sam|Samwise` in a Perl-like regex engine
1046/// will never match `Samwise` since `Sam` will always have higher priority.
1047/// Conversely, matching the regex `Samwise|Sam` against `Samwise` will lead to
1048/// a match of `Samwise` in both POSIX and Perl-like regexes since `Samwise` is
1049/// still longest match, but it also appears earlier than `Sam`.
1050///
1051/// The "standard" match semantics of Aho-Corasick generally don't correspond
1052/// to the match semantics of any large group of regex implementations, so
1053/// there's no direct analogy that can be made here. Standard match semantics
1054/// are generally useful for overlapping matches, or if you just want to see
1055/// matches as they are detected.
1056///
1057/// The main conclusion to draw from this section is that the match semantics
1058/// can be tweaked to precisely match either Perl-like regex alternations or
1059/// POSIX regex alternations.
1060#[non_exhaustive]
1061#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1062pub enum MatchKind {
1063    /// Use standard match semantics, which support overlapping matches. When
1064    /// used with non-overlapping matches, matches are reported as they are
1065    /// seen.
1066    Standard,
1067    /// Use leftmost-first match semantics, which reports leftmost matches.
1068    /// When there are multiple possible leftmost matches, the match
1069    /// corresponding to the pattern that appeared earlier when constructing
1070    /// the automaton is reported.
1071    ///
1072    /// This does **not** support overlapping matches or stream searching. If
1073    /// this match kind is used, attempting to find overlapping matches or
1074    /// stream matches will fail.
1075    LeftmostFirst,
1076    /// Use leftmost-longest match semantics, which reports leftmost matches.
1077    /// When there are multiple possible leftmost matches, the longest match
1078    /// is chosen.
1079    ///
1080    /// This does **not** support overlapping matches or stream searching. If
1081    /// this match kind is used, attempting to find overlapping matches or
1082    /// stream matches will fail.
1083    LeftmostLongest,
1084}
1085
1086/// The default match kind is `MatchKind::Standard`.
1087impl Default for MatchKind {
1088    fn default() -> MatchKind {
1089        MatchKind::Standard
1090    }
1091}
1092
1093impl MatchKind {
1094    #[inline]
1095    pub(crate) fn is_standard(&self) -> bool {
1096        matches!(*self, MatchKind::Standard)
1097    }
1098
1099    #[inline]
1100    pub(crate) fn is_leftmost(&self) -> bool {
1101        matches!(*self, MatchKind::LeftmostFirst | MatchKind::LeftmostLongest)
1102    }
1103
1104    #[inline]
1105    pub(crate) fn is_leftmost_first(&self) -> bool {
1106        matches!(*self, MatchKind::LeftmostFirst)
1107    }
1108
1109    /// Convert this match kind into a packed match kind. If this match kind
1110    /// corresponds to standard semantics, then this returns None, since
1111    /// packed searching does not support standard semantics.
1112    #[inline]
1113    pub(crate) fn as_packed(&self) -> Option<crate::packed::MatchKind> {
1114        match *self {
1115            MatchKind::Standard => None,
1116            MatchKind::LeftmostFirst => {
1117                Some(crate::packed::MatchKind::LeftmostFirst)
1118            }
1119            MatchKind::LeftmostLongest => {
1120                Some(crate::packed::MatchKind::LeftmostLongest)
1121            }
1122        }
1123    }
1124}
1125
1126/// The kind of anchored starting configurations to support in an Aho-Corasick
1127/// searcher.
1128///
1129/// Depending on which searcher is used internally by
1130/// [`AhoCorasick`](crate::AhoCorasick), supporting both unanchored
1131/// and anchored searches can be quite costly. For this reason,
1132/// [`AhoCorasickBuilder::start_kind`](crate::AhoCorasickBuilder::start_kind)
1133/// can be used to configure whether your searcher supports unanchored,
1134/// anchored or both kinds of searches.
1135///
1136/// This searcher configuration knob works in concert with the search time
1137/// configuration [`Input::anchored`]. Namely, if one requests an unsupported
1138/// anchored mode, then the search will either panic or return an error,
1139/// depending on whether you're using infallible or fallibe APIs, respectively.
1140///
1141/// `AhoCorasick` by default only supports unanchored searches.
1142#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1143pub enum StartKind {
1144    /// Support both anchored and unanchored searches.
1145    Both,
1146    /// Support only unanchored searches. Requesting an anchored search will
1147    /// return an error in fallible APIs and panic in infallible APIs.
1148    Unanchored,
1149    /// Support only anchored searches. Requesting an unanchored search will
1150    /// return an error in fallible APIs and panic in infallible APIs.
1151    Anchored,
1152}
1153
1154impl Default for StartKind {
1155    fn default() -> StartKind {
1156        StartKind::Unanchored
1157    }
1158}