pub trait Finder: Send + Sync {
Show 19 methods
// Required methods
fn id(&self) -> &'static str;
fn find(&self, s: &str) -> Option<Range<usize>>;
// Provided methods
fn dispatchable(&self) -> bool { ... }
fn could_start_at(&self, _byte: u8) -> bool { ... }
fn try_at(&self, _input: &[u8], _pos: usize) -> Option<Range<usize>> { ... }
fn could_start_after(&self, _prev: u8, _cur: u8) -> bool { ... }
fn could_continue_with(&self, _cur: u8, _next: u8) -> bool { ... }
fn try_at_memo(
&self,
input: &[u8],
pos: usize,
memo: &mut Memo,
) -> Option<Range<usize>> { ... }
fn try_trigger_at_memo(
&self,
input: &[u8],
pos: usize,
memo: &mut Memo,
) -> Option<Range<usize>> { ... }
fn line_agnostic(&self) -> bool { ... }
fn anchor(&self) -> Option<Anchor> { ... }
fn prefixes(&self) -> Vec<Vec<u8>> { ... }
fn run_rules(&self) -> Vec<RunRule> { ... }
fn triggerable(&self) -> bool { ... }
fn could_trigger_at(&self, _byte: u8) -> bool { ... }
fn has_trigger_context(&self) -> bool { ... }
fn trigger_context(&self, _prev2: u8, _prev1: u8) -> bool { ... }
fn trigger_context_exempt(&self, _next: Option<u8>) -> bool { ... }
fn try_trigger_at(&self, _input: &[u8], _pos: usize) -> Option<Range<usize>> { ... }
}Expand description
A trait for finding patterns in text.
All finders implement this trait. A finder implementation should be stateless; it’s up to the caller to call it repeatedly until no more results can be extracted.
§Contract
- Returned ranges are non-empty (
start < end) and lie on UTF-8 character boundaries. try_at/try_trigger_atreceive positions into the whole line and return absolute ranges.- Matches produced through the
scanner::Scannerare disjoint per finder and position-sorted.
Note that iterating with find over advancing sub-slices (as below) erases
the left context at each slice boundary, so finders that reject matches
based on what precedes them (e.g. a handle glued to a word) can accept a
match at position 0 of a sub-slice that the scanner::Scanner — which
always sees the whole line — would reject. The Scanner behavior is
authoritative; prefer it over hand-rolled find loops.
§Example
use squeeze::{uri::URI, Finder};
let finder = URI::default();
let text = "Check https://foo.com and https://bar.com";
let mut results = Vec::new();
let mut idx = 0;
while idx < text.len() {
if let Some(range) = finder.find(&text[idx..]) {
results.push(&text[idx + range.start..idx + range.end]);
idx += range.end;
} else {
break;
}
}
assert_eq!(results, vec!["https://foo.com", "https://bar.com"]);Required Methods§
Provided Methods§
Sourcefn dispatchable(&self) -> bool
fn dispatchable(&self) -> bool
Whether this finder supports dispatch-mode scanning via try_at.
Sourcefn could_start_at(&self, _byte: u8) -> bool
fn could_start_at(&self, _byte: u8) -> bool
Whether the given byte could be the first byte of a match.
Only meaningful when dispatchable returns true.
Sourcefn try_at(&self, _input: &[u8], _pos: usize) -> Option<Range<usize>>
fn try_at(&self, _input: &[u8], _pos: usize) -> Option<Range<usize>>
Try to find a match starting exactly at pos in the full input.
Only called when dispatchable returns true.
Sourcefn could_start_after(&self, _prev: u8, _cur: u8) -> bool
fn could_start_after(&self, _prev: u8, _cur: u8) -> bool
Whether a match could be attempted at byte cur when the byte
immediately before it is prev: a dispatch-mode start, or a
trigger-mode trigger byte.
Only meaningful when dispatchable or
triggerable returns true. Must agree with
try_at (or try_trigger_at):
whenever this returns false, the attempt must return None in that
context. The scanner::Scanner folds the answers into lookup tables
so positions that cannot start a match never reach the finder.
Sourcefn could_continue_with(&self, _cur: u8, _next: u8) -> bool
fn could_continue_with(&self, _cur: u8, _next: u8) -> bool
Whether an attempt at byte cur could succeed when the byte
immediately after it is next. Same contract as
could_start_after.
Sourcefn try_trigger_at_memo(
&self,
input: &[u8],
pos: usize,
memo: &mut Memo,
) -> Option<Range<usize>>
fn try_trigger_at_memo( &self, input: &[u8], pos: usize, memo: &mut Memo, ) -> Option<Range<usize>>
try_trigger_at with a per-line
Memo, same contract as try_at_memo.
Sourcefn line_agnostic(&self) -> bool
fn line_agnostic(&self) -> bool
Whether try_at/try_trigger_at give the same answer on a whole
buffer as on the line alone: \n and \r never belong to a match,
and every walk treats them exactly like the end of the input (as a
boundary), so a match never depends on what surrounds its line. A
finder that matches “up to the end of the line” (codetag), accepts
line terminators as whitespace (JSON, phone) or otherwise looks at
the line as a whole must keep the default. Line-agnostic finders are
run over whole buffers with absolute positions, which lets the
scanner skip resolving the line of every candidate; property tests
compare both modes. Defaults to false.
Sourcefn anchor(&self) -> Option<Anchor>
fn anchor(&self) -> Option<Anchor>
Bytes every match of this dispatch finder contains (bytes), and the
bytes that can separate a match start from the first of them
(walk). When every finder of a scanner declares an anchor (or is a
trigger finder) and the anchor bytes number three or fewer, the
scanner searches for those bytes with memchr, walks back over
walk and tries the dispatch positions in order, so lines without
an anchor byte cost nothing.
Contract: for every range try_at returns, some byte of the range is
in bytes, and every byte from the range start up to the first such
byte is in walk.
Sourcefn prefixes(&self) -> Vec<Vec<u8>>
fn prefixes(&self) -> Vec<Vec<u8>>
Byte strings, ASCII case ignored, one of which starts the input at
every position where try_at can match (todo
for --todo codetags). A finder that would otherwise need the block
classifier is then found by searching for them. Empty when unknown.
Contract: try_at(input, pos) returns None unless input[pos..]
starts with one of the prefixes, ASCII case ignored.
Sourcefn run_rules(&self) -> Vec<RunRule>
fn run_rules(&self) -> Vec<RunRule>
Rules on the digit or hex run starting at a candidate position,
evaluated with RunRule::allow before try_at
is called. Same contract as
could_start_after: when the rules
reject a position, try_at must return None there. The scanner
measures the runs once per position for all finders.
Sourcefn triggerable(&self) -> bool
fn triggerable(&self) -> bool
Whether this finder supports trigger-mode scanning.
Trigger-mode is for finders whose cheapest reliable signal is inside the
match rather than at the first byte, such as the @ in an email address
or : in a URI.
Sourcefn could_trigger_at(&self, _byte: u8) -> bool
fn could_trigger_at(&self, _byte: u8) -> bool
Whether the given byte could trigger a match for this finder.
Only meaningful when triggerable returns true.
Sourcefn has_trigger_context(&self) -> bool
fn has_trigger_context(&self) -> bool
Whether the trigger context gate constrains anything: the scanner
then tabulates trigger_context over the
65536 pairs of previous bytes and
trigger_context_exempt over the
next bytes, once, and consults them before calling the finder.
Defaults to false.
Sourcefn trigger_context(&self, _prev2: u8, _prev1: u8) -> bool
fn trigger_context(&self, _prev2: u8, _prev1: u8) -> bool
Whether a match may be triggered at a byte preceded by prev2 and
prev1, unless the byte after the trigger is exempt
(trigger_context_exempt): a
necessary condition for try_trigger_at
to match at that position. The scanner passes a space for a missing
previous byte (the trigger sits in the first two bytes of the
input). Defaults to true.
Sourcefn trigger_context_exempt(&self, _next: Option<u8>) -> bool
fn trigger_context_exempt(&self, _next: Option<u8>) -> bool
Whether a trigger followed by next (None at the end of the
input) escapes the previous-bytes condition: the URI finder needs a
registered scheme before a colon unless // follows. Defaults to
false.
Sourcefn try_trigger_at(&self, _input: &[u8], _pos: usize) -> Option<Range<usize>>
fn try_trigger_at(&self, _input: &[u8], _pos: usize) -> Option<Range<usize>>
Try to find a match triggered by pos in the full input.
Only called when triggerable returns true.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".