|
37 | 37 | )]
|
38 | 38 |
|
39 | 39 | use crate::fmt;
|
40 |
| -use crate::mem::replace; |
| 40 | +use crate::mem::{replace, take}; |
41 | 41 | use crate::ops::Range;
|
42 | 42 |
|
43 | 43 | /// A pattern which can be matched against a [`Haystack`].
|
@@ -201,6 +201,84 @@ pub enum SearchStep<T = usize> {
|
201 | 201 | Done,
|
202 | 202 | }
|
203 | 203 |
|
| 204 | +/// Possible return type of a search. |
| 205 | +/// |
| 206 | +/// It abstract differences between `next`, `next_match` and `next_reject` |
| 207 | +/// methods. Depending on return type an implementation for those functions |
| 208 | +/// will generate matches and rejects, only matches or only rejects. |
| 209 | +#[unstable(feature = "pattern_internals", issue = "none")] |
| 210 | +pub trait SearchResult<T = usize>: Sized + sealed::Sealed { |
| 211 | + /// Value indicating searching has finished. |
| 212 | + const DONE: Self; |
| 213 | + |
| 214 | + /// Returns value describing a match or `None` if this implementation |
| 215 | + /// doesn’t care about matches. |
| 216 | + fn matching(start: T, end: T) -> Option<Self>; |
| 217 | + |
| 218 | + /// Returns value describing a reject or `None` if this implementation |
| 219 | + /// doesn’t care about matches. |
| 220 | + fn rejecting(start: T, end: T) -> Option<Self>; |
| 221 | +} |
| 222 | + |
| 223 | +/// A wrapper for result type which only carries information about matches. |
| 224 | +#[unstable(feature = "pattern_internals", issue = "none")] |
| 225 | +#[derive(Copy, Clone, Eq, PartialEq, Debug)] |
| 226 | +pub struct MatchOnly<T = usize>(pub Option<(T, T)>); |
| 227 | + |
| 228 | +/// A wrapper for result type which only carries information about rejects. |
| 229 | +#[unstable(feature = "pattern_internals", issue = "none")] |
| 230 | +#[derive(Copy, Clone, Eq, PartialEq, Debug)] |
| 231 | +pub struct RejectOnly<T = usize>(pub Option<(T, T)>); |
| 232 | + |
| 233 | +impl<T> SearchResult<T> for SearchStep<T> { |
| 234 | + const DONE: Self = SearchStep::Done; |
| 235 | + |
| 236 | + #[inline(always)] |
| 237 | + fn matching(s: T, e: T) -> Option<Self> { |
| 238 | + Some(SearchStep::Match(s, e)) |
| 239 | + } |
| 240 | + |
| 241 | + #[inline(always)] |
| 242 | + fn rejecting(s: T, e: T) -> Option<Self> { |
| 243 | + Some(SearchStep::Reject(s, e)) |
| 244 | + } |
| 245 | +} |
| 246 | + |
| 247 | +impl<T> SearchResult<T> for MatchOnly<T> { |
| 248 | + const DONE: Self = Self(None); |
| 249 | + |
| 250 | + #[inline(always)] |
| 251 | + fn matching(s: T, e: T) -> Option<Self> { |
| 252 | + Some(Self(Some((s, e)))) |
| 253 | + } |
| 254 | + |
| 255 | + #[inline(always)] |
| 256 | + fn rejecting(_s: T, _e: T) -> Option<Self> { |
| 257 | + None |
| 258 | + } |
| 259 | +} |
| 260 | + |
| 261 | +impl<T> SearchResult<T> for RejectOnly<T> { |
| 262 | + const DONE: Self = Self(None); |
| 263 | + |
| 264 | + #[inline(always)] |
| 265 | + fn matching(_s: T, _e: T) -> Option<Self> { |
| 266 | + None |
| 267 | + } |
| 268 | + |
| 269 | + #[inline(always)] |
| 270 | + fn rejecting(s: T, e: T) -> Option<Self> { |
| 271 | + Some(Self(Some((s, e)))) |
| 272 | + } |
| 273 | +} |
| 274 | + |
| 275 | +mod sealed { |
| 276 | + pub trait Sealed {} |
| 277 | + impl<T> Sealed for super::SearchStep<T> {} |
| 278 | + impl<T> Sealed for super::MatchOnly<T> {} |
| 279 | + impl<T> Sealed for super::RejectOnly<T> {} |
| 280 | +} |
| 281 | + |
204 | 282 | /// A searcher for a string pattern.
|
205 | 283 | ///
|
206 | 284 | /// This trait provides methods for searching for non-overlapping matches of
|
@@ -363,6 +441,141 @@ pub unsafe trait ReverseSearcher<H: Haystack>: Searcher<H> {
|
363 | 441 | /// from which side it is searched.
|
364 | 442 | pub trait DoubleEndedSearcher<H: Haystack>: ReverseSearcher<H> {}
|
365 | 443 |
|
| 444 | +////////////////////////////////////////////////////////////////////////////// |
| 445 | +// Internal EmptyNeedleSearcher helper |
| 446 | +////////////////////////////////////////////////////////////////////////////// |
| 447 | + |
| 448 | +/// Helper for implementing searchers looking for empty patterns. |
| 449 | +/// |
| 450 | +/// An empty pattern matches around every element of a haystack. For example, |
| 451 | +/// within a `&str` it matches around every character. (This includes at the |
| 452 | +/// beginning and end of the string). |
| 453 | +/// |
| 454 | +/// This struct helps implement searchers for empty patterns for various |
| 455 | +/// haystacks. The only requirement is a function which advances the start |
| 456 | +/// position or end position of the haystack range. |
| 457 | +/// |
| 458 | +/// # Examples |
| 459 | +/// |
| 460 | +/// ``` |
| 461 | +/// #![feature(pattern, pattern_internals)] |
| 462 | +/// use core::pattern::{EmptyNeedleSearcher, SearchStep}; |
| 463 | +/// |
| 464 | +/// let haystack = "fóó"; |
| 465 | +/// let mut searcher = EmptyNeedleSearcher::new(haystack); |
| 466 | +/// let advance = |range: core::ops::Range<usize>| { |
| 467 | +/// range.start + haystack[range].chars().next().unwrap().len_utf8() |
| 468 | +/// }; |
| 469 | +/// let steps = core::iter::from_fn(|| { |
| 470 | +/// match searcher.next_fwd(advance) { |
| 471 | +/// SearchStep::Done => None, |
| 472 | +/// step => Some(step) |
| 473 | +/// } |
| 474 | +/// }).collect::<Vec<_>>(); |
| 475 | +/// assert_eq!(&[ |
| 476 | +/// SearchStep::Match(0, 0), |
| 477 | +/// SearchStep::Reject(0, 1), |
| 478 | +/// SearchStep::Match(1, 1), |
| 479 | +/// SearchStep::Reject(1, 3), |
| 480 | +/// SearchStep::Match(3, 3), |
| 481 | +/// SearchStep::Reject(3, 5), |
| 482 | +/// SearchStep::Match(5, 5), |
| 483 | +/// ], steps.as_slice()); |
| 484 | +/// ``` |
| 485 | +#[derive(Copy, Clone, Debug, PartialEq, Eq)] |
| 486 | +#[unstable(feature = "pattern_internals", issue = "none")] |
| 487 | +pub struct EmptyNeedleSearcher<T> { |
| 488 | + start: T, |
| 489 | + end: T, |
| 490 | + is_match_fwd: bool, |
| 491 | + is_match_bwd: bool, |
| 492 | + // Needed in case of an empty haystack, see #85462 |
| 493 | + is_finished: bool, |
| 494 | +} |
| 495 | + |
| 496 | +impl<T: Copy + PartialOrd> EmptyNeedleSearcher<T> { |
| 497 | + /// Creates a new empty needle searcher for given haystack. |
| 498 | + /// |
| 499 | + /// The haystack is used to initialise the range of valid cursors positions. |
| 500 | + pub fn new<H: Haystack<Cursor = T>>(haystack: H) -> Self { |
| 501 | + Self { |
| 502 | + start: haystack.cursor_at_front(), |
| 503 | + end: haystack.cursor_at_back(), |
| 504 | + is_match_bwd: true, |
| 505 | + is_match_fwd: true, |
| 506 | + is_finished: false, |
| 507 | + } |
| 508 | + } |
| 509 | + |
| 510 | + /// Returns next search result. |
| 511 | + /// |
| 512 | + /// The callback function is used to advance the **start** of the range the |
| 513 | + /// searcher is working on. It is passed the current range of cursor |
| 514 | + /// positions that weren’t visited yet and it must return the new start |
| 515 | + /// cursor position. It’s never called with an empty range. For some |
| 516 | + /// haystacks the callback may be as simple as a closure returning the start |
| 517 | + /// incremented by one; others might require looking for a new valid |
| 518 | + /// boundary. |
| 519 | + pub fn next_fwd<R: SearchResult<T>, F>(&mut self, advance_fwd: F) -> R |
| 520 | + where |
| 521 | + F: FnOnce(crate::ops::Range<T>) -> T, |
| 522 | + { |
| 523 | + if self.is_finished { |
| 524 | + return R::DONE; |
| 525 | + } |
| 526 | + if take(&mut self.is_match_fwd) { |
| 527 | + if let Some(ret) = R::matching(self.start, self.start) { |
| 528 | + return ret; |
| 529 | + } |
| 530 | + } |
| 531 | + if self.start < self.end { |
| 532 | + let pos = self.start; |
| 533 | + self.start = advance_fwd(self.start..self.end); |
| 534 | + if let Some(ret) = R::rejecting(pos, self.start) { |
| 535 | + self.is_match_fwd = true; |
| 536 | + return ret; |
| 537 | + } |
| 538 | + return R::matching(self.start, self.start).unwrap(); |
| 539 | + } |
| 540 | + self.is_finished = true; |
| 541 | + R::DONE |
| 542 | + } |
| 543 | + |
| 544 | + /// Returns next search result. |
| 545 | + /// |
| 546 | + /// The callback function is used to advance the **end** of the range the |
| 547 | + /// searcher is working on backwards. It is passed the current range of |
| 548 | + /// cursor positions that weren’t visited yet and it must return the new end |
| 549 | + /// cursor position. It’s never called with an empty range. For some |
| 550 | + /// haystacks the callback may be as simple as a closure returning the end |
| 551 | + /// decremented by one; others might require looking for a new valid |
| 552 | + /// boundary. |
| 553 | + pub fn next_bwd<R: SearchResult<T>, F>(&mut self, advance_bwd: F) -> R |
| 554 | + where |
| 555 | + F: FnOnce(crate::ops::Range<T>) -> T, |
| 556 | + { |
| 557 | + if self.is_finished { |
| 558 | + return R::DONE; |
| 559 | + } |
| 560 | + if take(&mut self.is_match_bwd) { |
| 561 | + if let Some(ret) = R::matching(self.end, self.end) { |
| 562 | + return ret; |
| 563 | + } |
| 564 | + } |
| 565 | + if self.start < self.end { |
| 566 | + let pos = self.end; |
| 567 | + self.end = advance_bwd(self.start..self.end); |
| 568 | + if let Some(ret) = R::rejecting(self.end, pos) { |
| 569 | + self.is_match_bwd = true; |
| 570 | + return ret; |
| 571 | + } |
| 572 | + return R::matching(self.end, self.end).unwrap(); |
| 573 | + } |
| 574 | + self.is_finished = true; |
| 575 | + R::DONE |
| 576 | + } |
| 577 | +} |
| 578 | + |
366 | 579 | //////////////////////////////////////////////////////////////////////////////
|
367 | 580 | // Internal Split and SplitN implementations
|
368 | 581 | //////////////////////////////////////////////////////////////////////////////
|
|
0 commit comments