1use alloc::borrow::Cow;
2use alloc::string::String;
3
4use crate::Captures;
5
6pub trait Replacer {
13    fn replace_append(&mut self, caps: &Captures<'_>, dst: &mut String);
21
22    fn no_expansion(&mut self) -> Option<Cow<str>> {
30        None
31    }
32
33    fn by_ref(&mut self) -> ReplacerRef<Self> {
55        ReplacerRef(self)
56    }
57}
58
59#[derive(Debug)]
63pub struct ReplacerRef<'a, R: ?Sized>(&'a mut R);
64
65impl<'a, R: Replacer + ?Sized + 'a> Replacer for ReplacerRef<'a, R> {
66    fn replace_append(&mut self, caps: &Captures<'_>, dst: &mut String) {
67        self.0.replace_append(caps, dst)
68    }
69    fn no_expansion(&mut self) -> Option<Cow<'_, str>> {
70        self.0.no_expansion()
71    }
72}
73
74impl<'a> Replacer for &'a str {
75    fn replace_append(&mut self, caps: &Captures<'_>, dst: &mut String) {
76        caps.expand(*self, dst);
77    }
78
79    fn no_expansion(&mut self) -> Option<Cow<'_, str>> {
80        no_expansion(self)
81    }
82}
83
84impl<'a> Replacer for &'a String {
85    fn replace_append(&mut self, caps: &Captures<'_>, dst: &mut String) {
86        self.as_str().replace_append(caps, dst)
87    }
88
89    fn no_expansion(&mut self) -> Option<Cow<'_, str>> {
90        no_expansion(self)
91    }
92}
93
94impl Replacer for String {
95    fn replace_append(&mut self, caps: &Captures<'_>, dst: &mut String) {
96        self.as_str().replace_append(caps, dst)
97    }
98
99    fn no_expansion(&mut self) -> Option<Cow<'_, str>> {
100        no_expansion(self)
101    }
102}
103
104impl<'a> Replacer for Cow<'a, str> {
105    fn replace_append(&mut self, caps: &Captures<'_>, dst: &mut String) {
106        self.as_ref().replace_append(caps, dst)
107    }
108
109    fn no_expansion(&mut self) -> Option<Cow<'_, str>> {
110        no_expansion(self)
111    }
112}
113
114impl<'a> Replacer for &'a Cow<'a, str> {
115    fn replace_append(&mut self, caps: &Captures<'_>, dst: &mut String) {
116        self.as_ref().replace_append(caps, dst)
117    }
118
119    fn no_expansion(&mut self) -> Option<Cow<'_, str>> {
120        no_expansion(self)
121    }
122}
123
124fn no_expansion<T: AsRef<str>>(t: &T) -> Option<Cow<'_, str>> {
125    let s = t.as_ref();
126    if s.contains('$') {
127        None
128    } else {
129        Some(Cow::Borrowed(s))
130    }
131}
132
133impl<F, T> Replacer for F
134where
135    F: FnMut(&Captures<'_>) -> T,
136    T: AsRef<str>,
137{
138    fn replace_append(&mut self, caps: &Captures<'_>, dst: &mut String) {
139        dst.push_str((*self)(caps).as_ref());
140    }
141}
142
143#[derive(Clone, Debug)]
152pub struct NoExpand<'t>(pub &'t str);
153
154impl<'t> Replacer for NoExpand<'t> {
155    fn replace_append(&mut self, _: &Captures<'_>, dst: &mut String) {
156        dst.push_str(self.0);
157    }
158
159    fn no_expansion(&mut self) -> Option<Cow<'_, str>> {
160        Some(Cow::Borrowed(self.0))
161    }
162}