1use alloc::borrow::Cow;
2use alloc::string::String;
34use crate::Captures;
56/// Replacer describes types that can be used to replace matches in a string.
7///
8/// In general, users of this crate shouldn't need to implement this trait,
9/// since implementations are already provided for `&str` along with other
10/// variants of string types and `FnMut(&Captures) -> String` (or any
11/// `FnMut(&Captures) -> T` where `T: AsRef<str>`), which covers most use cases.
12pub trait Replacer {
13/// Appends text to `dst` to replace the current match.
14 ///
15 /// The current match is represented by `caps`, which is guaranteed to
16 /// have a match at capture group `0`.
17 ///
18 /// For example, a no-op replacement would be
19 /// `dst.push_str(caps.get(0).unwrap().as_str())`.
20fn replace_append(&mut self, caps: &Captures<'_>, dst: &mut String);
2122/// Return a fixed unchanging replacement string.
23 ///
24 /// When doing replacements, if access to `Captures` is not needed (e.g.,
25 /// the replacement byte string does not need `$` expansion), then it can
26 /// be beneficial to avoid finding sub-captures.
27 ///
28 /// In general, this is called once for every call to `replacen`.
29fn no_expansion(&mut self) -> Option<Cow<str>> {
30None
31}
3233/// Return a `Replacer` that borrows and wraps this `Replacer`.
34 ///
35 /// This is useful when you want to take a generic `Replacer` (which might
36 /// not be cloneable) and use it without consuming it, so it can be used
37 /// more than once.
38 ///
39 /// # Example
40 ///
41 /// ```
42 /// use fancy_regex::{Regex, Replacer};
43 ///
44 /// fn replace_all_twice<R: Replacer>(
45 /// re: Regex,
46 /// src: &str,
47 /// mut rep: R,
48 /// ) -> String {
49 /// let dst = re.replace_all(src, rep.by_ref());
50 /// let dst = re.replace_all(&dst, rep.by_ref());
51 /// dst.into_owned()
52 /// }
53 /// ```
54fn by_ref(&mut self) -> ReplacerRef<Self> {
55 ReplacerRef(self)
56 }
57}
5859/// By-reference adaptor for a `Replacer`
60///
61/// Returned by [`Replacer::by_ref`](trait.Replacer.html#method.by_ref).
62#[derive(Debug)]
63pub struct ReplacerRef<'a, R: ?Sized>(&'a mut R);
6465impl<'a, R: Replacer + ?Sized + 'a> Replacer for ReplacerRef<'a, R> {
66fn replace_append(&mut self, caps: &Captures<'_>, dst: &mut String) {
67self.0.replace_append(caps, dst)
68 }
69fn no_expansion(&mut self) -> Option<Cow<'_, str>> {
70self.0.no_expansion()
71 }
72}
7374impl<'a> Replacer for &'a str {
75fn replace_append(&mut self, caps: &Captures<'_>, dst: &mut String) {
76 caps.expand(*self, dst);
77 }
7879fn no_expansion(&mut self) -> Option<Cow<'_, str>> {
80 no_expansion(self)
81 }
82}
8384impl<'a> Replacer for &'a String {
85fn replace_append(&mut self, caps: &Captures<'_>, dst: &mut String) {
86self.as_str().replace_append(caps, dst)
87 }
8889fn no_expansion(&mut self) -> Option<Cow<'_, str>> {
90 no_expansion(self)
91 }
92}
9394impl Replacer for String {
95fn replace_append(&mut self, caps: &Captures<'_>, dst: &mut String) {
96self.as_str().replace_append(caps, dst)
97 }
9899fn no_expansion(&mut self) -> Option<Cow<'_, str>> {
100 no_expansion(self)
101 }
102}
103104impl<'a> Replacer for Cow<'a, str> {
105fn replace_append(&mut self, caps: &Captures<'_>, dst: &mut String) {
106self.as_ref().replace_append(caps, dst)
107 }
108109fn no_expansion(&mut self) -> Option<Cow<'_, str>> {
110 no_expansion(self)
111 }
112}
113114impl<'a> Replacer for &'a Cow<'a, str> {
115fn replace_append(&mut self, caps: &Captures<'_>, dst: &mut String) {
116self.as_ref().replace_append(caps, dst)
117 }
118119fn no_expansion(&mut self) -> Option<Cow<'_, str>> {
120 no_expansion(self)
121 }
122}
123124fn no_expansion<T: AsRef<str>>(t: &T) -> Option<Cow<'_, str>> {
125let s = t.as_ref();
126if s.contains('$') {
127None
128} else {
129Some(Cow::Borrowed(s))
130 }
131}
132133impl<F, T> Replacer for F
134where
135F: FnMut(&Captures<'_>) -> T,
136 T: AsRef<str>,
137{
138fn replace_append(&mut self, caps: &Captures<'_>, dst: &mut String) {
139 dst.push_str((*self)(caps).as_ref());
140 }
141}
142143/// `NoExpand` indicates literal string replacement.
144///
145/// It can be used with `replace` and `replace_all` to do a literal string
146/// replacement without expanding `$name` to their corresponding capture
147/// groups. This can be both convenient (to avoid escaping `$`, for example)
148/// and performant (since capture groups don't need to be found).
149///
150/// `'t` is the lifetime of the literal text.
151#[derive(Clone, Debug)]
152pub struct NoExpand<'t>(pub &'t str);
153154impl<'t> Replacer for NoExpand<'t> {
155fn replace_append(&mut self, _: &Captures<'_>, dst: &mut String) {
156 dst.push_str(self.0);
157 }
158159fn no_expansion(&mut self) -> Option<Cow<'_, str>> {
160Some(Cow::Borrowed(self.0))
161 }
162}