From d89b31a18637e0cecfef1f1d4a73164cb7a9d16d Mon Sep 17 00:00:00 2001 From: Jan Behrens Date: Sat, 22 Jul 2023 12:46:55 +0200 Subject: [PATCH] fixup! More generic impl of Replacer for closures Refactored code to be able to use two different lifetimes `'a` and `'b` for the `&'a Captures<'b>` argument while allowing the return type to depend on either `'a` or `'b`. --- src/regex/string.rs | 26 +++++++++++++------------- tests/misc.rs | 16 ---------------- 2 files changed, 13 insertions(+), 29 deletions(-) diff --git a/src/regex/string.rs b/src/regex/string.rs index d94f06c54..f3829932d 100644 --- a/src/regex/string.rs +++ b/src/regex/string.rs @@ -2374,18 +2374,18 @@ impl<'c, 'h> core::iter::FusedIterator for SubCaptureMatches<'c, 'h> {} /// Contains helper trait for blanket implementation for [`Replacer`]. mod replacer_closure { use super::*; - /// If a closure implements this for all `'a`, then it also implements - /// [`Replacer`]. - pub trait ReplacerClosure<'a> + /// If a closure implements this for all `&'a Captures<'b>`, then it also + /// implements [`Replacer`]. + pub trait ReplacerClosure where - Self: FnMut(&'a Captures<'a>) -> >::Output, + Self: FnMut(Arg) -> >::Output, { - /// Return type of the closure (may depend on lifetime `'a`). + /// Return type of the closure (may depend on lifetime `'a` or `'b`). type Output: AsRef; } - impl<'a, F: ?Sized, O> ReplacerClosure<'a> for F + impl<'a, 'b, F, O> ReplacerClosure<&'a Captures<'b>> for F where - F: FnMut(&'a Captures<'a>) -> O, + F: ?Sized + FnMut(&'a Captures<'b>) -> O, O: AsRef, { type Output = O; @@ -2428,8 +2428,8 @@ use replacer_closure::*; /// /// # Implementation by closures /// -/// Closures that take an argument of type `&'a Captures<'b>` for any `'a` and -/// `'b: 'a` and which return a type `T: AsRef` (that may depend on `'a` +/// Closures that take an argument of type `&'a Captures<'b>` (for any `'a` +/// and `'b`) and which return a type `T: AsRef` (that may depend on `'a` /// or `'b`) implement the `Replacer` trait through a [blanket implementation]. /// /// [blanket implementation]: Self#impl-Replacer-for-F @@ -2575,18 +2575,18 @@ impl<'a> Replacer for &'a Cow<'a, str> { /// Blanket implementation of `Replacer` for closures. /// /// This implementation is basically the following, except that the return type -/// `T` may optionally depend on lifetime `'a`. +/// `T` may optionally depend on the lifetimes `'a` and `'b`. /// /// ```ignore /// impl Replacer for F /// where -/// F: for<'a> FnMut(&'a Captures<'a>) -> T, -/// T: AsRef, // `T` may also depend on `'a`, which cannot be expressed easily +/// F: for<'a, 'b> FnMut(&'a Captures<'b>) -> T, +/// T: AsRef, // `T` may depend on `'a` or `'b`, which can't be expressed easily /// { /// /* … */ /// } /// ``` -impl ReplacerClosure<'a>> Replacer for F { +impl ReplacerClosure<&'a Captures<'b>>> Replacer for F { fn replace_append(&mut self, caps: &Captures<'_>, dst: &mut String) { dst.push_str((*self)(caps).as_ref()); } diff --git a/tests/misc.rs b/tests/misc.rs index d4ae31feb..9cb7d7746 100644 --- a/tests/misc.rs +++ b/tests/misc.rs @@ -170,20 +170,4 @@ mod replacer_closure_lifetimes { ); assert_eq!(s, "x"); } - // Additionally demand that its sufficient if the closure accepts a single - // lifetime `'u` which is used both for the reference to and the lifetime - // argument of the `Captures` argument. Note that `Captures<'u>` is - // covariant over `'u`. - #[test] - fn unified_lifetime() { - fn coerce FnMut(&'u Captures<'u>) -> Cow<'u, str>>( - f: F, - ) -> F { - f - } - let s = Regex::new("x") - .unwrap() - .replace_all("x", coerce(|caps| Cow::Borrowed(&caps[0]))); - assert_eq!(s, "x"); - } }