Conditional regex replacement

Indeed, we could make our own trait with blanket implementation (aka trait alias) to work around this (just hypothetically exploring this idea):

pub trait GenericFnOnce1Arg<Arg>
where
    Self: FnOnce(Arg) -> <Self as GenericFnOnce1Arg<Arg>>::Output
{
    type Output;
}

impl<T: ?Sized, Arg, Ret> GenericFnOnce1Arg<Arg> for T
where T: FnOnce(Arg) -> Ret,
{
    type Output = Ret;
}

Now we can use a bound like that:

fn use_it<F>(_val: F)
where
    F: for<'a> GenericFnOnce1Arg<&'a Outer>,
{}

Here, the return type does not need to be named (but could have additional bounds added, like AsRef<str>, if desired [1]).

Now, using the nightly #![feature(closure_lifetime_binder), we can use this API:

fn f(o: &Outer) -> &Inner {
    &o.field
}

fn main() {
    use_it(for<'a> |outer: &'a Outer| -> &'a Inner { &outer.field });
    use_it(f);
}

(Playground)


Update: Combining all these ideas, and getting back to the original problem, we could do:

#![feature(closure_lifetime_binder)]

struct MyReplacer<F>(F);

impl<F> Replacer for MyReplacer<F>
where
    F: for<'a> GenericFnMut1Arg<&'a Captures<'a>>,
    for<'a> <F as GenericFnMut1Arg<&'a Captures<'a>>>::Output: AsRef<str>,
{
    fn replace_append(&mut self, caps: &Captures<'_>, dst: &mut String) {
        dst.push_str((self.0)(caps).as_ref())
    }
}

fn main() {
    let s1 = "Hello World!";
    let s2 = Regex::new("World").unwrap().replace_all(s1, "Universe");
    assert_eq!(s2, "Hello Universe!");
    let s3 = Regex::new("World").unwrap().replace_all(
        s1,
        MyReplacer(
            for<'a> |caps: &'a Captures<'a>| -> &'a str {
                let universal: bool = false; // actually some more complex computation
                if universal {
                    "Universe"
                } else {
                    &caps[0] // don't replace
                }
            }
        )
    );
    assert_eq!(s3, "Hello World!");
}

(Playground)

I don't want to say it's a good or idiomatic way to go. But it's curious that it's possible to solve this issue in that way (on Nightly, and being willing to use a newtype wrapper to adjust regex's API)!


  1. (Playground) ↩︎

1 Like