Skip to content

Commit

Permalink
regex: add Replacer::by_ref adaptor
Browse files Browse the repository at this point in the history
This permits use of a Replacer without consuming it.

Note: This can't simply return `&mut Self` because a generic
`impl<R: Replacer> Replacer for &mut R` would conflict with libstd's
generic `impl<F: FnMut> FnMut for &mut F`.

See also: rust-lang#83

Closes rust-lang#449
  • Loading branch information
mbrubeck authored and BurntSushi committed Mar 7, 2018
1 parent 7645ff2 commit 7f020b8
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ pub use re_trait::Locations;
pub use re_unicode::{
Regex, Match, Captures,
CaptureNames, Matches, CaptureMatches, SubCaptureMatches,
Replacer, NoExpand, Split, SplitN,
Replacer, ReplacerRef, NoExpand, Split, SplitN,
escape,
};

Expand Down
40 changes: 40 additions & 0 deletions src/re_bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -990,6 +990,46 @@ pub trait Replacer {
fn no_expansion<'r>(&'r mut self) -> Option<Cow<'r, [u8]>> {
None
}

/// Return a `Replacer` that borrows and wraps this `Replacer`.
///
/// This is useful when you want to take a generic `Replacer` (which might
/// not be cloneable) and use it without consuming it, so it can be used
/// more than once.
///
/// # Example
///
/// ```
/// use regex::bytes::{Regex, Replacer};
///
/// fn replace_all_twice<R: Replacer>(
/// re: Regex,
/// src: &[u8],
/// mut rep: R,
/// ) -> Vec<u8> {
/// let dst = re.replace_all(src, rep.by_ref());
/// let dst = re.replace_all(&dst, rep.by_ref());
/// dst.into_owned()
/// }
/// ```
fn by_ref<'r>(&'r mut self) -> ReplacerRef<'r, Self> {
ReplacerRef(self)
}
}

/// By-reference adaptor for a `Replacer`
///
/// Returned by [`Replacer::by_ref`](trait.Replacer.html#method.by_ref).
#[derive(Debug)]
pub struct ReplacerRef<'a, R: ?Sized + 'a>(&'a mut R);

impl<'a, R: Replacer + ?Sized + 'a> Replacer for ReplacerRef<'a, R> {
fn replace_append(&mut self, caps: &Captures, dst: &mut Vec<u8>) {
self.0.replace_append(caps, dst)
}
fn no_expansion<'r>(&'r mut self) -> Option<Cow<'r, [u8]>> {
self.0.no_expansion()
}
}

impl<'a> Replacer for &'a [u8] {
Expand Down
40 changes: 40 additions & 0 deletions src/re_unicode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1034,6 +1034,46 @@ pub trait Replacer {
fn no_expansion<'r>(&'r mut self) -> Option<Cow<'r, str>> {
None
}

/// Return a `Replacer` that borrows and wraps this `Replacer`.
///
/// This is useful when you want to take a generic `Replacer` (which might
/// not be cloneable) and use it without consuming it, so it can be used
/// more than once.
///
/// # Example
///
/// ```
/// use regex::{Regex, Replacer};
///
/// fn replace_all_twice<R: Replacer>(
/// re: Regex,
/// src: &str,
/// mut rep: R,
/// ) -> String {
/// let dst = re.replace_all(src, rep.by_ref());
/// let dst = re.replace_all(&dst, rep.by_ref());
/// dst.into_owned()
/// }
/// ```
fn by_ref<'r>(&'r mut self) -> ReplacerRef<'r, Self> {
ReplacerRef(self)
}
}

/// By-reference adaptor for a `Replacer`
///
/// Returned by [`Replacer::by_ref`](trait.Replacer.html#method.by_ref).
#[derive(Debug)]
pub struct ReplacerRef<'a, R: ?Sized + 'a>(&'a mut R);

impl<'a, R: Replacer + ?Sized + 'a> Replacer for ReplacerRef<'a, R> {
fn replace_append(&mut self, caps: &Captures, dst: &mut String) {
self.0.replace_append(caps, dst)
}
fn no_expansion(&mut self) -> Option<Cow<str>> {
self.0.no_expansion()
}
}

impl<'a> Replacer for &'a str {
Expand Down

0 comments on commit 7f020b8

Please sign in to comment.