1use std::collections::TryReserveError;
2use std::fmt::{Debug, Display};
3use std::marker::PhantomData;
4use std::ops::{AddAssign, Bound, Deref, DerefMut, Range, RangeBounds};
5use std::string::Drain;
6
7use crate::helper::macros::{default_impl_ref_observe, untracked_methods};
8use crate::helper::{AsDerefMut, AsNormalized, Pointer, Succ, Unsigned, Zero};
9use crate::observe::{DefaultSpec, Observer, SerializeObserver};
10use crate::{Adapter, MutationKind, Mutations, Observe};
11
12pub struct StringObserver<'ob, S: ?Sized, D = Zero> {
14 ptr: Pointer<S>,
15 mutation: Option<TruncateAppend>,
16 phantom: PhantomData<&'ob mut D>,
17}
18
19struct TruncateAppend {
20 pub append_index: usize, pub truncate_len: usize, }
23
24impl<'ob, S: ?Sized, D> StringObserver<'ob, S, D> {
25 #[inline]
26 fn __mark_replace(&mut self) {
27 self.mutation = None;
28 }
29}
30
31impl<'ob, S: ?Sized, D> Deref for StringObserver<'ob, S, D> {
32 type Target = Pointer<S>;
33
34 #[inline]
35 fn deref(&self) -> &Self::Target {
36 &self.ptr
37 }
38}
39
40impl<'ob, S: ?Sized, D> DerefMut for StringObserver<'ob, S, D> {
41 #[inline]
42 fn deref_mut(&mut self) -> &mut Self::Target {
43 self.__mark_replace();
44 &mut self.ptr
45 }
46}
47
48impl<'ob, S: ?Sized, D> AsNormalized for StringObserver<'ob, S, D> {
49 type OuterDepth = Succ<Zero>;
50}
51
52impl<'ob, S: ?Sized, D> Observer<'ob> for StringObserver<'ob, S, D>
53where
54 D: Unsigned,
55 S: AsDerefMut<D, Target = String> + 'ob,
56{
57 type InnerDepth = D;
58 type Head = S;
59
60 #[inline]
61 fn uninit() -> Self {
62 Self {
63 ptr: Pointer::uninit(),
64 mutation: None,
65 phantom: PhantomData,
66 }
67 }
68
69 #[inline]
70 fn observe(value: &mut Self::Head) -> Self {
71 Self {
72 ptr: Pointer::new(value),
73 mutation: Some(TruncateAppend {
74 append_index: value.as_deref().len(),
75 truncate_len: 0,
76 }),
77 phantom: PhantomData,
78 }
79 }
80
81 #[inline]
82 unsafe fn refresh(this: &mut Self, value: &mut Self::Head) {
83 Pointer::set(this, value);
84 }
85}
86
87impl<'ob, S: ?Sized, D> SerializeObserver<'ob> for StringObserver<'ob, S, D>
88where
89 D: Unsigned,
90 S: AsDerefMut<D, Target = String> + 'ob,
91{
92 unsafe fn flush_unchecked<A: Adapter>(this: &mut Self) -> Result<Mutations<A::Value>, A::Error> {
93 let len = this.as_deref().len();
94 let Some(truncate_append) = this.mutation.replace(TruncateAppend {
95 append_index: len,
96 truncate_len: 0,
97 }) else {
98 return Ok(MutationKind::Replace(A::serialize_value(this.as_deref())?).into());
99 };
100 let TruncateAppend {
101 append_index,
102 truncate_len,
103 } = truncate_append;
104 let mut mutations = Mutations::new();
105 #[cfg(feature = "truncate")]
106 if truncate_len > 0 {
107 mutations.extend(MutationKind::Truncate(truncate_len));
108 }
109 #[cfg(feature = "append")]
110 if len > append_index {
111 mutations.extend(MutationKind::Append(A::serialize_value(
112 &this.as_deref()[append_index..],
113 )?));
114 }
115 Ok(mutations)
116 }
117}
118
119impl<'ob, S: ?Sized, D> StringObserver<'ob, S, D>
120where
121 D: Unsigned,
122 S: AsDerefMut<D, Target = String>,
123{
124 untracked_methods! { String =>
125 pub fn reserve(&mut self, additional: usize);
126 pub fn reserve_exact(&mut self, additional: usize);
127 pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError>;
128 pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError>;
129 pub fn shrink_to_fit(&mut self);
130 pub fn shrink_to(&mut self, min_capacity: usize);
131 }
132}
133
134#[cfg(feature = "append")]
135impl<'ob, S: ?Sized, D> StringObserver<'ob, S, D>
136where
137 D: Unsigned,
138 S: AsDerefMut<D, Target = String> + 'ob,
139{
140 #[inline]
141 fn __append_index(&mut self) -> usize {
142 match &mut self.mutation {
143 Some(m) => m.append_index,
144 None => 0,
145 }
146 }
147
148 untracked_methods! { String =>
149 pub fn push(&mut self, c: char);
150 pub fn push_str(&mut self, s: &str);
151 pub fn extend_from_within<R>(&mut self, src: R)
152 where { R: RangeBounds<usize> };
153 }
154
155 #[inline]
157 pub fn insert(&mut self, idx: usize, ch: char) {
158 if idx >= self.__append_index() {
159 Observer::as_inner(self).insert(idx, ch)
160 } else {
161 Observer::track_inner(self).insert(idx, ch)
162 }
163 }
164
165 #[inline]
167 pub fn insert_str(&mut self, idx: usize, string: &str) {
168 if idx >= self.__append_index() {
169 Observer::as_inner(self).insert_str(idx, string)
170 } else {
171 Observer::track_inner(self).insert_str(idx, string)
172 }
173 }
174}
175
176#[cfg(any(feature = "truncate", feature = "append"))]
177impl<'ob, S: ?Sized, D> StringObserver<'ob, S, D>
178where
179 D: Unsigned,
180 S: AsDerefMut<D, Target = String> + 'ob,
181{
182 #[inline]
183 fn __mark_truncate(&mut self, range: Range<usize>) {
184 let count = self.as_deref()[range.clone()].chars().count();
185 let mutation = self.mutation.as_mut().unwrap();
186 mutation.truncate_len += count;
187 mutation.append_index = range.start;
188 }
189
190 #[inline]
192 pub fn clear(&mut self) {
193 if self.__append_index() == 0 {
194 Observer::as_inner(self).clear()
195 } else {
196 Observer::track_inner(self).clear()
197 }
198 }
199
200 pub fn remove(&mut self, idx: usize) -> char {
202 let char = Observer::as_inner(self).remove(idx);
203 let append_index = self.__append_index();
204 if idx >= append_index {
205 } else if cfg!(feature = "truncate") && idx + char.len_utf8() == append_index {
207 let mutation = self.mutation.as_mut().unwrap();
208 mutation.truncate_len += 1;
209 mutation.append_index = idx;
210 } else {
211 self.__mark_replace();
212 }
213 char
214 }
215
216 pub fn pop(&mut self) -> Option<char> {
218 let char = Observer::as_inner(self).pop()?;
219 let append_index = self.__append_index();
220 let len = self.as_deref().len();
221 if len >= append_index {
222 } else if cfg!(feature = "truncate") && len + char.len_utf8() == append_index {
224 let mutation = self.mutation.as_mut().unwrap();
225 mutation.truncate_len += 1;
226 mutation.append_index = len;
227 } else {
228 self.__mark_replace();
229 }
230 Some(char)
231 }
232
233 pub fn truncate(&mut self, len: usize) {
235 let append_index = self.__append_index();
236 if len >= append_index {
237 return Observer::as_inner(self).truncate(len);
238 }
239 if cfg!(not(feature = "truncate")) || len == 0 {
240 return Observer::track_inner(self).truncate(len);
241 }
242 self.__mark_truncate(len..append_index);
243 Observer::as_inner(self).truncate(len)
244 }
245
246 pub fn split_off(&mut self, at: usize) -> String {
248 let append_index = self.__append_index();
249 if at >= append_index {
250 return Observer::as_inner(self).split_off(at);
251 }
252 if cfg!(not(feature = "truncate")) || at == 0 {
253 return Observer::track_inner(self).split_off(at);
254 }
255 self.__mark_truncate(at..append_index);
256 Observer::as_inner(self).split_off(at)
257 }
258
259 pub fn drain<R>(&mut self, range: R) -> Drain<'_>
261 where
262 R: RangeBounds<usize>,
263 {
264 let append_index = self.__append_index();
265 let start_index = match range.start_bound() {
266 Bound::Included(&n) => n,
267 Bound::Excluded(&n) => n + 1,
268 Bound::Unbounded => 0,
269 };
270 if start_index >= append_index {
271 return Observer::as_inner(self).drain(range);
272 }
273 if cfg!(not(feature = "truncate")) || start_index == 0 {
274 return Observer::track_inner(self).drain(range);
275 }
276 let end_index = match range.end_bound() {
277 Bound::Included(&n) => n + 1,
278 Bound::Excluded(&n) => n,
279 Bound::Unbounded => self.as_deref().len(),
280 };
281 if end_index < append_index {
282 return Observer::track_inner(self).drain(range);
283 }
284 self.__mark_truncate(start_index..append_index);
285 Observer::track_inner(self).drain(range)
286 }
287
288 pub fn replace_range<R>(&mut self, range: R, replace_with: &str)
290 where
291 R: RangeBounds<usize>,
292 {
293 let append_index = self.__append_index();
294 let start_index = match range.start_bound() {
295 Bound::Included(&n) => n,
296 Bound::Excluded(&n) => n + 1,
297 Bound::Unbounded => 0,
298 };
299 if start_index >= append_index {
300 return Observer::as_inner(self).replace_range(range, replace_with);
301 }
302 if cfg!(not(feature = "truncate")) || start_index == 0 {
303 return Observer::track_inner(self).replace_range(range, replace_with);
304 }
305 let end_index = match range.end_bound() {
306 Bound::Included(&n) => n + 1,
307 Bound::Excluded(&n) => n,
308 Bound::Unbounded => self.as_deref().len(),
309 };
310 if end_index < append_index {
311 return Observer::track_inner(self).replace_range(range, replace_with);
312 }
313 self.__mark_truncate(start_index..append_index);
314 Observer::as_inner(self).replace_range(range, replace_with);
315 }
316}
317
318impl<'ob, S: ?Sized, D> AddAssign<&str> for StringObserver<'ob, S, D>
319where
320 D: Unsigned,
321 S: AsDerefMut<D, Target = String> + 'ob,
322{
323 #[inline]
324 fn add_assign(&mut self, rhs: &str) {
325 #[cfg(feature = "append")]
326 self.push_str(rhs);
327 #[cfg(not(feature = "append"))]
328 Observer::track_inner(self).add_assign(rhs);
329 }
330}
331
332#[cfg(feature = "append")]
333impl<'ob, S: ?Sized, D, U> Extend<U> for StringObserver<'ob, S, D>
334where
335 D: Unsigned,
336 S: AsDerefMut<D, Target = String>,
337 String: Extend<U>,
338{
339 #[inline]
340 fn extend<I: IntoIterator<Item = U>>(&mut self, other: I) {
341 Observer::as_inner(self).extend(other);
342 }
343}
344
345impl<'ob, S: ?Sized, D> Debug for StringObserver<'ob, S, D>
346where
347 D: Unsigned,
348 S: AsDerefMut<D, Target = String>,
349{
350 #[inline]
351 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
352 f.debug_tuple("StringObserver").field(self.as_deref()).finish()
353 }
354}
355
356impl<'ob, S: ?Sized, D> Display for StringObserver<'ob, S, D>
357where
358 D: Unsigned,
359 S: AsDerefMut<D, Target = String>,
360{
361 #[inline]
362 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
363 Display::fmt(self.as_deref(), f)
364 }
365}
366
367impl<'ob, S, D, U: ?Sized> PartialEq<U> for StringObserver<'ob, S, D>
368where
369 D: Unsigned,
370 S: AsDerefMut<D, Target = String>,
371 String: PartialEq<U>,
372{
373 #[inline]
374 fn eq(&self, other: &U) -> bool {
375 self.as_deref().eq(other)
376 }
377}
378
379impl<'ob, S, D, U: ?Sized> PartialOrd<U> for StringObserver<'ob, S, D>
380where
381 D: Unsigned,
382 S: AsDerefMut<D, Target = String>,
383 String: PartialOrd<U>,
384{
385 #[inline]
386 fn partial_cmp(&self, other: &U) -> Option<std::cmp::Ordering> {
387 self.as_deref().partial_cmp(other)
388 }
389}
390
391impl Observe for String {
392 type Observer<'ob, S, D>
393 = StringObserver<'ob, S, D>
394 where
395 Self: 'ob,
396 D: Unsigned,
397 S: AsDerefMut<D, Target = Self> + ?Sized + 'ob;
398
399 type Spec = DefaultSpec;
400}
401
402default_impl_ref_observe! {
403 impl RefObserve for String;
404}
405
406#[cfg(test)]
407mod tests {
408 use serde_json::json;
409
410 use super::*;
411 use crate::Mutation;
412 use crate::adapter::Json;
413 use crate::observe::{ObserveExt, SerializeObserverExt};
414
415 #[test]
416 fn no_mutation_returns_none() {
417 let mut s = String::from("hello");
418 let mut ob = s.__observe();
419 let Json(mutation) = ob.flush().unwrap();
420 assert!(mutation.is_none());
421 }
422
423 #[test]
424 fn replace_on_deref_mut() {
425 let mut s = String::from("hello");
426 let mut ob = s.__observe();
427 ob.clear();
428 ob.push_str("world"); let Json(mutation) = ob.flush().unwrap();
430 assert_eq!(
431 mutation,
432 Some(Mutation {
433 path: vec![].into(),
434 kind: MutationKind::Replace(json!("world"))
435 })
436 );
437 }
438
439 #[test]
440 fn append_with_push() {
441 let mut s = String::from("a");
442 let mut ob = s.__observe();
443 ob.push('b');
444 ob.push('c');
445 let Json(mutation) = ob.flush().unwrap();
446 assert_eq!(
447 mutation,
448 Some(Mutation {
449 path: vec![].into(),
450 kind: MutationKind::Append(json!("bc"))
451 })
452 );
453 }
454
455 #[test]
456 fn append_with_push_str() {
457 let mut s = String::from("foo");
458 let mut ob = s.__observe();
459 ob.push_str("bar");
460 let Json(mutation) = ob.flush().unwrap();
461 assert_eq!(
462 mutation,
463 Some(Mutation {
464 path: vec![].into(),
465 kind: MutationKind::Append(json!("bar"))
466 })
467 );
468 }
469
470 #[test]
471 fn append_with_add_assign() {
472 let mut s = String::from("foo");
473 let mut ob = s.__observe();
474 ob += "bar";
475 let Json(mutation) = ob.flush().unwrap();
476 assert_eq!(mutation.unwrap().kind, MutationKind::Append(json!("bar")));
477 }
478
479 #[test]
480 fn append_empty_string() {
481 let mut s = String::from("foo");
482 let mut ob = s.__observe();
483 ob.push_str("");
484 ob += "";
485 let Json(mutation) = ob.flush().unwrap();
486 assert!(mutation.is_none());
487 }
488
489 #[test]
490 fn replace_after_append() {
491 let mut s = String::from("abc");
492 let mut ob = s.__observe();
493 ob.push_str("def");
494 **ob = String::from("xyz");
495 let Json(mutation) = ob.flush().unwrap();
496 assert_eq!(mutation.unwrap().kind, MutationKind::Replace(json!("xyz")));
497 }
498
499 #[test]
500 fn truncate() {
501 let mut s = String::from("你好,世界!");
502 let mut ob = s.__observe();
503 ob.truncate("你好".len());
504 let Json(mutation) = ob.flush().unwrap();
505 assert_eq!(mutation.unwrap().kind, MutationKind::Truncate(4));
506 }
507
508 #[test]
509 fn pop_as_truncate() {
510 let mut s = String::from("你好,世界!");
511 let mut ob = s.__observe();
512 ob.pop();
513 ob.pop();
514 let Json(mutation) = ob.flush().unwrap();
515 assert_eq!(mutation.unwrap().kind, MutationKind::Truncate(2));
516 }
517
518 #[test]
519 fn pop_after_append() {
520 let mut s = String::from("你好!");
521 let mut ob = s.__observe();
522 ob.push_str("世界!");
523 ob.pop();
524 let Json(mutation) = ob.flush().unwrap();
525 assert_eq!(mutation.unwrap().kind, MutationKind::Append(json!("世界")));
526 }
527
528 #[test]
529 fn append_after_pop() {
530 let mut s = String::from("你好,世界!");
531 let mut ob = s.__observe();
532 ob.pop();
533 ob.push('~');
534 let Json(mutation) = ob.flush().unwrap();
535 assert_eq!(
536 mutation.unwrap().kind,
537 MutationKind::Batch(vec![
538 Mutation {
539 path: Default::default(),
540 kind: MutationKind::Truncate(1),
541 },
542 Mutation {
543 path: Default::default(),
544 kind: MutationKind::Append(json!("~")),
545 },
546 ])
547 );
548 }
549
550 #[test]
551 fn remove_before_append_index() {
552 let mut s = String::from("你好,世界!");
553 let mut ob = s.__observe();
554 assert_eq!(ob.remove("你好".len()), ',');
555 let Json(mutation) = ob.flush().unwrap();
556 assert_eq!(mutation.unwrap().kind, MutationKind::Replace(json!("你好世界!")));
557 }
558
559 #[test]
560 fn remove_at_append_index() {
561 let mut s = String::from("你好,世界!");
562 let mut ob = s.__observe();
563 assert_eq!(ob.remove("你好,世界".len()), '!');
564 assert_eq!(ob.remove("你好,世".len()), '界');
565 let Json(mutation) = ob.flush().unwrap();
566 assert_eq!(mutation.unwrap().kind, MutationKind::Truncate(2));
567 }
568}