1use core::{
16 marker::PhantomData,
17 ops::{Bound, Deref, DerefMut, RangeBounds},
18};
19
20pub(crate) trait GenericString: Deref<Target = str> + DerefMut<Target = str> {
21 fn set_size(&mut self, size: usize);
22 fn as_mut_capacity_slice(&mut self) -> &mut [u8];
23}
24
25macro_rules! string_op_grow {
26 ($action:ty, $target:ident, $($arg:expr),*) => {
27 match $target.cast_mut() {
28 StringCastMut::Boxed(this) => {
29 this.ensure_capacity(<$action>::cap(this, $($arg),*));
30 <$action>::op(this, $($arg),*)
31 }
32 StringCastMut::Inline(this) => {
33 let new_size = <$action>::cap(this,$($arg),*);
34 if new_size > MAX_INLINE {
35 let mut new_str = BoxedString::from_str(new_size, this);
36 let result = <$action>::op(&mut new_str, $($arg),*);
37 $target.promote_from(new_str);
38 result
39 } else {
40 <$action>::op(this, $($arg),*)
41 }
42 }
43 }
44 };
45}
46pub(crate) use string_op_grow;
47
48macro_rules! string_op_shrink {
49 ($action:ty, $target:ident, $($arg:expr),*) => {{
50 let result = match $target.cast_mut() {
51 StringCastMut::Boxed(this) => {
52 <$action>::op(this, $($arg),*)
53 }
54 StringCastMut::Inline(this) => {
55 <$action>::op(this, $($arg),*)
56 }
57 };
58 $target.try_demote();
59 result
60 }};
61
62 ($action:ty, $target:ident) => {
63 string_op_shrink!($action, $target,)
64 }
65}
66pub(crate) use string_op_shrink;
67
68use crate::{SmartString, SmartStringMode};
69
70pub(crate) fn bounds_for<R>(range: &R, max_len: usize) -> (usize, usize)
71where
72 R: RangeBounds<usize>,
73{
74 let start = match range.start_bound() {
75 Bound::Included(&n) => n,
76 Bound::Excluded(&n) => n.checked_add(1).unwrap(),
77 Bound::Unbounded => 0,
78 };
79 let end = match range.end_bound() {
80 Bound::Included(&n) => n.checked_add(1).unwrap(),
81 Bound::Excluded(&n) => n,
82 Bound::Unbounded => max_len,
83 };
84 (start, end)
85}
86
87fn insert_bytes<S: GenericString>(this: &mut S, index: usize, src: &[u8]) {
88 let len = this.len();
89 let src_len = src.len();
90 let tail_index = index + src_len;
91 if src_len > 0 {
92 let buf = this.as_mut_capacity_slice();
93 buf.copy_within(index..len, tail_index);
94 buf[index..tail_index].copy_from_slice(src);
95 this.set_size(len + src_len);
96 }
97}
98
99pub(crate) struct PushStr;
100impl PushStr {
101 pub(crate) fn cap<S: GenericString>(this: &S, string: &str) -> usize {
102 this.len() + string.len()
103 }
104
105 pub(crate) fn op<S: GenericString>(this: &mut S, string: &str) {
106 let len = this.len();
107 let new_len = len + string.len();
108 this.as_mut_capacity_slice()[len..new_len].copy_from_slice(string.as_bytes());
109 this.set_size(new_len);
110 }
111}
112
113pub(crate) struct Push;
114impl Push {
115 pub(crate) fn cap<S: GenericString>(this: &S, ch: char) -> usize {
116 this.len() + ch.len_utf8()
117 }
118
119 pub(crate) fn op<S: GenericString>(this: &mut S, ch: char) {
120 let len = this.len();
121 let written = ch
122 .encode_utf8(&mut this.as_mut_capacity_slice()[len..])
123 .len();
124 this.set_size(len + written);
125 }
126}
127
128pub(crate) struct Truncate;
129impl Truncate {
130 pub(crate) fn op<S: GenericString>(this: &mut S, new_len: usize) {
131 if new_len < this.len() {
132 assert!(this.deref().is_char_boundary(new_len));
133 this.set_size(new_len)
134 }
135 }
136}
137
138pub(crate) struct Pop;
139impl Pop {
140 pub(crate) fn op<S: GenericString>(this: &mut S) -> Option<char> {
141 let ch = this.deref().chars().rev().next()?;
142 this.set_size(this.len() - ch.len_utf8());
143 Some(ch)
144 }
145}
146
147pub(crate) struct Remove;
148impl Remove {
149 pub(crate) fn op<S: GenericString>(this: &mut S, index: usize) -> char {
150 let ch = match this.deref()[index..].chars().next() {
151 Some(ch) => ch,
152 None => panic!("cannot remove a char from the end of a string"),
153 };
154 let next = index + ch.len_utf8();
155 let len = this.len();
156 let tail_len = len - next;
157 if tail_len > 0 {
158 this.as_mut_capacity_slice().copy_within(next..len, index);
159 }
160 this.set_size(len - (next - index));
161 ch
162 }
163}
164
165pub(crate) struct Insert;
166impl Insert {
167 pub(crate) fn cap<S: GenericString>(this: &S, index: usize, ch: char) -> usize {
168 assert!(this.deref().is_char_boundary(index));
169 this.len() + ch.len_utf8()
170 }
171
172 pub(crate) fn op<S: GenericString>(this: &mut S, index: usize, ch: char) {
173 let mut buffer = [0; 4];
174 let buffer = ch.encode_utf8(&mut buffer).as_bytes();
175 insert_bytes(this, index, buffer);
176 }
177}
178
179pub(crate) struct InsertStr;
180impl InsertStr {
181 pub(crate) fn cap<S: GenericString>(this: &S, index: usize, string: &str) -> usize {
182 assert!(this.deref().is_char_boundary(index));
183 this.len() + string.len()
184 }
185
186 pub(crate) fn op<S: GenericString>(this: &mut S, index: usize, string: &str) {
187 insert_bytes(this, index, string.as_bytes());
188 }
189}
190
191pub(crate) struct SplitOff<Mode: SmartStringMode>(PhantomData<Mode>);
192impl<Mode: SmartStringMode> SplitOff<Mode> {
193 pub(crate) fn op<S: GenericString>(this: &mut S, index: usize) -> SmartString<Mode> {
194 assert!(this.deref().is_char_boundary(index));
195 let result = this.deref()[index..].into();
196 this.set_size(index);
197 result
198 }
199}
200
201pub(crate) struct Retain;
202impl Retain {
203 pub(crate) fn op<F, S>(this: &mut S, mut f: F)
204 where
205 F: FnMut(char) -> bool,
206 S: GenericString,
207 {
208 let len = this.len();
209 let mut del_bytes = 0;
210 let mut index = 0;
211
212 while index < len {
213 let ch = this
214 .deref_mut()
215 .get(index..len)
216 .unwrap()
217 .chars()
218 .next()
219 .unwrap();
220 let ch_len = ch.len_utf8();
221
222 if !f(ch) {
223 del_bytes += ch_len;
224 } else if del_bytes > 0 {
225 this.as_mut_capacity_slice()
226 .copy_within(index..index + ch_len, index - del_bytes);
227 }
228 index += ch_len;
229 }
230
231 if del_bytes > 0 {
232 this.set_size(len - del_bytes);
233 }
234 }
235}
236
237pub(crate) struct ReplaceRange;
238impl ReplaceRange {
239 pub(crate) fn cap<R, S>(this: &S, range: &R, replace_with: &str) -> usize
240 where
241 R: RangeBounds<usize>,
242 S: GenericString,
243 {
244 let len = this.len();
245 let (start, end) = bounds_for(range, len);
246 assert!(end >= start);
247 assert!(end <= len);
248 assert!(this.deref().is_char_boundary(start));
249 assert!(this.deref().is_char_boundary(end));
250 let replace_len = replace_with.len();
251 let end_size = len - end;
252 start + replace_len + end_size
253 }
254
255 pub(crate) fn op<R, S>(this: &mut S, range: &R, replace_with: &str)
256 where
257 R: RangeBounds<usize>,
258 S: GenericString,
259 {
260 let len = this.len();
261 let (start, end) = bounds_for(range, len);
262 let replace_len = replace_with.len();
263 let new_end = start + replace_len;
264 let end_size = len - end;
265 this.as_mut_capacity_slice().copy_within(end..len, new_end);
266 if replace_len > 0 {
267 this.as_mut_capacity_slice()[start..new_end].copy_from_slice(replace_with.as_bytes());
268 }
269 this.set_size(start + replace_len + end_size);
270 }
271}