1#![allow(clippy::missing_safety_doc)]
2#![cfg_attr(feature = "nightly", feature(pattern))]
3#![cfg_attr(feature = "nightly", feature(slice_range))]
4#![cfg_attr(feature = "nightly", feature(extend_one))]
5#![cfg_attr(feature = "nightly", feature(min_specialization))]
6#![cfg_attr(feature = "nightly", feature(fmt_internals))]
7
8use std::{
9 borrow::Cow,
10 char::{decode_utf16, REPLACEMENT_CHARACTER},
11 fmt, hash,
12 iter::{FromIterator, FusedIterator},
13 ops::{self, Add, AddAssign, Index, IndexMut, Range, RangeBounds},
14 ptr,
15 str::{from_utf8, from_utf8_unchecked, from_utf8_unchecked_mut, Chars, FromStr, Utf8Error},
16};
17#[cfg(feature = "nightly")]
18use std::{iter::from_fn, slice, str::pattern::Pattern};
19
20use thin_vec::ThinVec;
21
22#[derive(PartialOrd, Eq, Ord)]
23pub struct ThinString {
24 vec: ThinVec<u8>,
25}
26
27#[derive(Debug, PartialEq, Eq, Clone)]
28pub struct FromUtf8Error {
29 bytes: ThinVec<u8>,
30 error: Utf8Error,
31}
32
33pub struct FromUtf16Error(());
34
35impl ThinString {
36 #[inline]
37 pub fn new() -> ThinString {
38 ThinString {
39 vec: ThinVec::new(),
40 }
41 }
42
43 #[inline]
44 pub fn with_capacity(capacity: usize) -> ThinString {
45 ThinString {
46 vec: ThinVec::with_capacity(capacity),
47 }
48 }
49
50 #[inline]
51 pub fn from_utf8(vec: ThinVec<u8>) -> Result<ThinString, FromUtf8Error> {
52 match from_utf8(&vec) {
53 Ok(..) => Ok(ThinString { vec }),
54 Err(e) => Err(FromUtf8Error {
55 bytes: vec,
56 error: e,
57 }),
58 }
59 }
60
61 #[inline]
62 pub fn from_utf8_lossy(v: &[u8]) -> ThinString {
63 let mut iter = v.utf8_chunks();
64
65 let first_valid = if let Some(chunk) = iter.next() {
66 let valid = chunk.valid();
67 if chunk.invalid().is_empty() {
68 debug_assert_eq!(valid.len(), v.len());
69 return ThinString::from(valid);
70 }
71 valid
72 } else {
73 return ThinString::new();
74 };
75
76 const REPLACEMENT: &str = "\u{FFFD}";
77
78 let mut res = ThinString::with_capacity(v.len());
79 res.push_str(first_valid);
80 res.push_str(REPLACEMENT);
81
82 for chunk in iter {
83 res.push_str(chunk.valid());
84 if !chunk.invalid().is_empty() {
85 res.push_str(REPLACEMENT);
86 }
87 }
88
89 res
90 }
91
92 #[inline]
93 pub fn from_utf16(v: &[u16]) -> Result<ThinString, FromUtf16Error> {
94 let mut ret = ThinString::with_capacity(v.len());
95 for c in decode_utf16(v.iter().cloned()) {
96 if let Ok(c) = c {
97 ret.push(c);
98 } else {
99 return Err(FromUtf16Error(()));
100 }
101 }
102 Ok(ret)
103 }
104
105 #[inline]
106 pub fn from_utf16_lossy(v: &[u16]) -> ThinString {
107 decode_utf16(v.iter().cloned())
108 .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))
109 .collect()
110 }
111
112 #[inline]
113 pub unsafe fn from_utf8_unchecked(bytes: ThinVec<u8>) -> ThinString {
114 ThinString { vec: bytes }
115 }
116
117 #[inline]
118 pub fn into_bytes(self) -> ThinVec<u8> {
119 self.vec
120 }
121
122 #[inline]
123 pub fn as_str(&self) -> &str {
124 self
125 }
126
127 #[inline]
128 pub fn as_mut_str(&mut self) -> &mut str {
129 self
130 }
131
132 #[inline]
133 pub fn push_str(&mut self, string: &str) {
134 self.vec.extend_from_slice(string.as_bytes())
135 }
136
137 #[inline]
138 pub fn capacity(&self) -> usize {
139 self.vec.capacity()
140 }
141
142 #[inline]
143 pub fn reserve(&mut self, additional: usize) {
144 self.vec.reserve(additional)
145 }
146
147 #[inline]
148 pub fn reserve_exact(&mut self, additional: usize) {
149 self.vec.reserve_exact(additional)
150 }
151
152 #[inline]
153 pub fn shrink_to_fit(&mut self) {
154 self.vec.shrink_to_fit()
155 }
156
157 #[inline]
158 pub fn push(&mut self, ch: char) {
159 match ch.len_utf8() {
160 1 => self.vec.push(ch as u8),
161 _ => self
162 .vec
163 .extend_from_slice(ch.encode_utf8(&mut [0; 4]).as_bytes()),
164 }
165 }
166
167 #[inline]
168 pub fn as_bytes(&self) -> &[u8] {
169 &self.vec
170 }
171
172 #[inline]
173 pub fn truncate(&mut self, new_len: usize) {
174 if new_len <= self.len() {
175 assert!(self.is_char_boundary(new_len));
176 self.vec.truncate(new_len)
177 }
178 }
179
180 #[inline]
181 pub fn pop(&mut self) -> Option<char> {
182 let ch = self.chars().rev().next()?;
183 let newlen = self.len() - ch.len_utf8();
184 unsafe {
185 self.vec.set_len(newlen);
186 }
187 Some(ch)
188 }
189
190 #[inline]
191 pub fn remove(&mut self, idx: usize) -> char {
192 let ch = match self[idx..].chars().next() {
193 Some(ch) => ch,
194 None => panic!("cannot remove a char from the end of a string"),
195 };
196
197 let next = idx + ch.len_utf8();
198 let len = self.len();
199 unsafe {
200 ptr::copy(
201 self.vec.as_ptr().add(next),
202 self.vec.as_mut_ptr().add(idx),
203 len - next,
204 );
205 self.vec.set_len(len - (next - idx));
206 }
207 ch
208 }
209
210 #[cfg(feature = "nightly")]
211 pub fn remove_matches<P: Pattern>(&mut self, pat: P) {
212 use core::str::pattern::Searcher;
213
214 let rejections = {
215 let mut searcher = pat.into_searcher(self);
216 let mut front = 0;
226 let rejections: Vec<_> = from_fn(|| {
227 let (start, end) = searcher.next_match()?;
228 let prev_front = front;
229 front = end;
230 Some((prev_front, start))
231 })
232 .collect();
233 rejections
234 .into_iter()
235 .chain(core::iter::once((front, self.len())))
236 };
237
238 let mut len = 0;
239 let ptr = self.vec.as_mut_ptr();
240
241 for (start, end) in rejections {
242 let count = end - start;
243 if start != len {
244 unsafe {
251 ptr::copy(ptr.add(start), ptr.add(len), count);
252 }
253 }
254 len += count;
255 }
256
257 unsafe {
258 self.vec.set_len(len);
259 }
260 }
261
262 #[inline]
263 pub fn retain<F>(&mut self, mut f: F)
264 where
265 F: FnMut(char) -> bool,
266 {
267 struct SetLenOnDrop<'a> {
268 s: &'a mut ThinString,
269 idx: usize,
270 del_bytes: usize,
271 }
272
273 impl<'a> Drop for SetLenOnDrop<'a> {
274 fn drop(&mut self) {
275 let new_len = self.idx - self.del_bytes;
276 debug_assert!(new_len <= self.s.len());
277 unsafe { self.s.vec.set_len(new_len) };
278 }
279 }
280
281 let len = self.len();
282 let mut guard = SetLenOnDrop {
283 s: self,
284 idx: 0,
285 del_bytes: 0,
286 };
287
288 while guard.idx < len {
289 let ch = unsafe {
290 guard
291 .s
292 .get_unchecked(guard.idx..len)
293 .chars()
294 .next()
295 .unwrap()
296 };
297 let ch_len = ch.len_utf8();
298
299 if !f(ch) {
300 guard.del_bytes += ch_len;
301 } else if guard.del_bytes > 0 {
302 unsafe {
303 ptr::copy(
304 guard.s.vec.as_slice().as_ptr().add(guard.idx),
305 guard
306 .s
307 .vec
308 .as_mut_slice()
309 .as_mut_ptr()
310 .add(guard.idx - guard.del_bytes),
311 ch_len,
312 );
313 }
314 }
315
316 guard.idx += ch_len;
318 }
319
320 drop(guard);
321 }
322
323 #[inline]
324 pub fn insert(&mut self, idx: usize, ch: char) {
325 assert!(self.is_char_boundary(idx));
326 let mut bits = [0; 4];
327 let bits = ch.encode_utf8(&mut bits).as_bytes();
328
329 unsafe {
330 self.insert_bytes(idx, bits);
331 }
332 }
333
334 unsafe fn insert_bytes(&mut self, idx: usize, bytes: &[u8]) {
335 let len = self.len();
336 let amt = bytes.len();
337 self.vec.reserve(amt);
338
339 ptr::copy(
340 self.vec.as_slice().as_ptr().add(idx),
341 self.vec.as_mut_slice().as_mut_ptr().add(idx + amt),
342 len - idx,
343 );
344 ptr::copy_nonoverlapping(bytes.as_ptr(), self.vec.as_mut_ptr().add(idx), amt);
345 self.vec.set_len(len + amt);
346 }
347
348 #[inline]
349 pub fn insert_str(&mut self, idx: usize, string: &str) {
350 assert!(self.is_char_boundary(idx));
351
352 unsafe {
353 self.insert_bytes(idx, string.as_bytes());
354 }
355 }
356
357 #[inline]
358 pub unsafe fn as_mut_vec(&mut self) -> &mut ThinVec<u8> {
359 &mut self.vec
360 }
361
362 #[inline]
363 pub fn len(&self) -> usize {
364 self.vec.len()
365 }
366
367 #[inline]
368 pub fn is_empty(&self) -> bool {
369 self.len() == 0
370 }
371
372 #[inline]
373 #[must_use = "use `.truncate()` if you don't need the other half"]
374 pub fn split_off(&mut self, at: usize) -> ThinString {
375 assert!(self.is_char_boundary(at));
376 let other = self.vec.split_off(at);
377 unsafe { ThinString::from_utf8_unchecked(other) }
378 }
379
380 #[inline]
381 pub fn clear(&mut self) {
382 self.vec.clear()
383 }
384
385 #[inline]
386 pub fn drain<R>(&mut self, range: R) -> Drain<'_>
387 where
388 R: RangeBounds<usize>,
389 {
390 #[cfg(not(feature = "nightly"))]
391 #[track_caller]
393 #[must_use]
394 pub fn std_slice_range<R>(range: R, bounds: ops::RangeTo<usize>) -> ops::Range<usize>
395 where
396 R: ops::RangeBounds<usize>,
397 {
398 let len = bounds.end;
399
400 let start = match range.start_bound() {
401 ops::Bound::Included(&start) => start,
402 ops::Bound::Excluded(start) => start
403 .checked_add(1)
404 .unwrap_or_else(|| panic!("attempted to index slice from after maximum usize")),
405 ops::Bound::Unbounded => 0,
406 };
407
408 let end = match range.end_bound() {
409 ops::Bound::Included(end) => end
410 .checked_add(1)
411 .unwrap_or_else(|| panic!("attempted to index slice up to maximum usize")),
412 ops::Bound::Excluded(&end) => end,
413 ops::Bound::Unbounded => len,
414 };
415
416 if start > end {
417 panic!("slice index starts at {} but ends at {}", start, end);
418 }
419 if end > len {
420 panic!(
421 "range end index {} out of range for slice of length {}",
422 end, len
423 );
424 }
425
426 ops::Range { start, end }
427 }
428 #[cfg(feature = "nightly")]
429 use std::slice::range as std_slice_range;
430
431 let Range { start, end } = std_slice_range(range, ..self.len());
438 assert!(self.is_char_boundary(start));
439 assert!(self.is_char_boundary(end));
440
441 let self_ptr = self as *mut _;
444 let chars_iter = unsafe { self.get_unchecked(start..end) }.chars();
446
447 Drain {
448 start,
449 end,
450 iter: chars_iter,
451 string: self_ptr,
452 }
453 }
454}
455
456impl FromUtf8Error {
457 #[inline]
458 pub fn as_bytes(&self) -> &[u8] {
459 &self.bytes[..]
460 }
461
462 #[inline]
463 pub fn into_bytes(self) -> ThinVec<u8> {
464 self.bytes
465 }
466
467 #[inline]
468 pub fn utf8_error(&self) -> Utf8Error {
469 self.error
470 }
471}
472
473impl fmt::Display for FromUtf8Error {
474 #[inline]
475 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
476 fmt::Display::fmt(&self.error, f)
477 }
478}
479
480impl fmt::Display for FromUtf16Error {
481 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
482 fmt::Display::fmt("invalid utf-16: lone surrogate found", f)
483 }
484}
485
486impl Clone for ThinString {
487 fn clone(&self) -> Self {
488 ThinString {
489 vec: self.vec.clone(),
490 }
491 }
492
493 fn clone_from(&mut self, source: &Self) {
494 self.vec.clone_from(&source.vec);
495 }
496}
497
498impl FromIterator<char> for ThinString {
499 fn from_iter<I: IntoIterator<Item = char>>(iter: I) -> ThinString {
500 let mut buf = ThinString::new();
501 buf.extend(iter);
502 buf
503 }
504}
505
506impl<'a> FromIterator<&'a char> for ThinString {
507 fn from_iter<I: IntoIterator<Item = &'a char>>(iter: I) -> ThinString {
508 let mut buf = ThinString::new();
509 buf.extend(iter);
510 buf
511 }
512}
513
514impl<'a> FromIterator<&'a str> for ThinString {
515 fn from_iter<I: IntoIterator<Item = &'a str>>(iter: I) -> ThinString {
516 let mut buf = ThinString::new();
517 buf.extend(iter);
518 buf
519 }
520}
521
522impl FromIterator<ThinString> for ThinString {
523 fn from_iter<I: IntoIterator<Item = ThinString>>(iter: I) -> ThinString {
524 let mut iterator = iter.into_iter();
525
526 match iterator.next() {
530 None => ThinString::new(),
531 Some(mut buf) => {
532 buf.extend(iterator);
533 buf
534 }
535 }
536 }
537}
538
539impl FromIterator<Box<str>> for ThinString {
540 fn from_iter<I: IntoIterator<Item = Box<str>>>(iter: I) -> ThinString {
541 let mut buf = ThinString::new();
542 buf.extend(iter);
543 buf
544 }
545}
546
547impl<'a> FromIterator<Cow<'a, str>> for ThinString {
548 fn from_iter<I: IntoIterator<Item = Cow<'a, str>>>(iter: I) -> ThinString {
549 let mut iterator = iter.into_iter();
550
551 match iterator.next() {
555 None => ThinString::new(),
556 Some(cow) => {
557 let mut buf = cow.to_thin_string();
558 buf.extend(iterator);
559 buf
560 }
561 }
562 }
563}
564
565impl Extend<char> for ThinString {
566 fn extend<I: IntoIterator<Item = char>>(&mut self, iter: I) {
567 let iterator = iter.into_iter();
568 let (lower_bound, _) = iterator.size_hint();
569 self.reserve(lower_bound);
570 iterator.for_each(move |c| self.push(c));
571 }
572
573 #[cfg(feature = "nightly")]
574 #[inline]
575 fn extend_one(&mut self, c: char) {
576 self.push(c);
577 }
578
579 #[cfg(feature = "nightly")]
580 #[inline]
581 fn extend_reserve(&mut self, additional: usize) {
582 self.reserve(additional);
583 }
584}
585
586impl<'a> Extend<&'a char> for ThinString {
587 fn extend<I: IntoIterator<Item = &'a char>>(&mut self, iter: I) {
588 self.extend(iter.into_iter().cloned());
589 }
590
591 #[cfg(feature = "nightly")]
592 #[inline]
593 fn extend_one(&mut self, &c: &'a char) {
594 self.push(c);
595 }
596
597 #[cfg(feature = "nightly")]
598 #[inline]
599 fn extend_reserve(&mut self, additional: usize) {
600 self.reserve(additional);
601 }
602}
603
604impl<'a> Extend<&'a str> for ThinString {
605 fn extend<I: IntoIterator<Item = &'a str>>(&mut self, iter: I) {
606 iter.into_iter().for_each(move |s| self.push_str(s));
607 }
608
609 #[cfg(feature = "nightly")]
610 #[inline]
611 fn extend_one(&mut self, s: &'a str) {
612 self.push_str(s);
613 }
614}
615
616impl Extend<Box<str>> for ThinString {
617 fn extend<I: IntoIterator<Item = Box<str>>>(&mut self, iter: I) {
618 iter.into_iter().for_each(move |s| self.push_str(&s));
619 }
620}
621
622impl Extend<ThinString> for ThinString {
623 fn extend<I: IntoIterator<Item = ThinString>>(&mut self, iter: I) {
624 iter.into_iter().for_each(move |s| self.push_str(&s));
625 }
626
627 #[cfg(feature = "nightly")]
628 #[inline]
629 fn extend_one(&mut self, s: ThinString) {
630 self.push_str(&s);
631 }
632}
633
634impl<'a> Extend<Cow<'a, str>> for ThinString {
635 fn extend<I: IntoIterator<Item = Cow<'a, str>>>(&mut self, iter: I) {
636 iter.into_iter().for_each(move |s| self.push_str(&s));
637 }
638
639 #[cfg(feature = "nightly")]
640 #[inline]
641 fn extend_one(&mut self, s: Cow<'a, str>) {
642 self.push_str(&s);
643 }
644}
645
646impl PartialEq for ThinString {
647 #[inline]
648 fn eq(&self, other: &ThinString) -> bool {
649 PartialEq::eq(&self[..], &other[..])
650 }
651 #[inline]
652 fn ne(&self, other: &ThinString) -> bool {
653 PartialEq::ne(&self[..], &other[..])
654 }
655}
656
657#[doc(hidden)]
658macro_rules! impl_eq {
659 ($lhs:ty, $rhs: ty) => {
660 #[allow(unused_lifetimes)]
661 impl<'a, 'b> PartialEq<$rhs> for $lhs {
662 #[inline]
663 fn eq(&self, other: &$rhs) -> bool {
664 PartialEq::eq(&self[..], &other[..])
665 }
666 #[inline]
667 fn ne(&self, other: &$rhs) -> bool {
668 PartialEq::ne(&self[..], &other[..])
669 }
670 }
671
672 #[allow(unused_lifetimes)]
673 impl<'a, 'b> PartialEq<$lhs> for $rhs {
674 #[inline]
675 fn eq(&self, other: &$lhs) -> bool {
676 PartialEq::eq(&self[..], &other[..])
677 }
678 #[inline]
679 fn ne(&self, other: &$lhs) -> bool {
680 PartialEq::ne(&self[..], &other[..])
681 }
682 }
683 };
684}
685
686impl_eq! { ThinString, str }
687impl_eq! { ThinString, &'a str }
688impl_eq! { Cow<'a, str>, ThinString }
689
690impl Default for ThinString {
691 #[inline]
693 fn default() -> ThinString {
694 ThinString::new()
695 }
696}
697
698impl fmt::Display for ThinString {
699 #[inline]
700 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
701 fmt::Display::fmt(&**self, f)
702 }
703}
704
705impl fmt::Debug for ThinString {
706 #[inline]
707 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
708 fmt::Debug::fmt(&**self, f)
709 }
710}
711
712impl hash::Hash for ThinString {
713 #[inline]
714 fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
715 (**self).hash(hasher)
716 }
717}
718
719impl Add<&str> for ThinString {
720 type Output = ThinString;
721
722 #[inline]
723 fn add(mut self, other: &str) -> ThinString {
724 self.push_str(other);
725 self
726 }
727}
728
729impl AddAssign<&str> for ThinString {
730 #[inline]
731 fn add_assign(&mut self, other: &str) {
732 self.push_str(other);
733 }
734}
735
736impl ops::Index<ops::Range<usize>> for ThinString {
737 type Output = str;
738
739 #[inline]
740 fn index(&self, index: ops::Range<usize>) -> &str {
741 &self[..][index]
742 }
743}
744
745impl ops::Index<ops::RangeTo<usize>> for ThinString {
746 type Output = str;
747
748 #[inline]
749 fn index(&self, index: ops::RangeTo<usize>) -> &str {
750 &self[..][index]
751 }
752}
753
754impl ops::Index<ops::RangeFrom<usize>> for ThinString {
755 type Output = str;
756
757 #[inline]
758 fn index(&self, index: ops::RangeFrom<usize>) -> &str {
759 &self[..][index]
760 }
761}
762
763impl ops::Index<ops::RangeFull> for ThinString {
764 type Output = str;
765
766 #[inline]
767 fn index(&self, _index: ops::RangeFull) -> &str {
768 unsafe { from_utf8_unchecked(&self.vec) }
769 }
770}
771
772impl ops::Index<ops::RangeInclusive<usize>> for ThinString {
773 type Output = str;
774
775 #[inline]
776 fn index(&self, index: ops::RangeInclusive<usize>) -> &str {
777 Index::index(&**self, index)
778 }
779}
780
781impl ops::Index<ops::RangeToInclusive<usize>> for ThinString {
782 type Output = str;
783
784 #[inline]
785 fn index(&self, index: ops::RangeToInclusive<usize>) -> &str {
786 Index::index(&**self, index)
787 }
788}
789
790impl ops::IndexMut<ops::Range<usize>> for ThinString {
791 #[inline]
792 fn index_mut(&mut self, index: ops::Range<usize>) -> &mut str {
793 &mut self[..][index]
794 }
795}
796
797impl ops::IndexMut<ops::RangeTo<usize>> for ThinString {
798 #[inline]
799 fn index_mut(&mut self, index: ops::RangeTo<usize>) -> &mut str {
800 &mut self[..][index]
801 }
802}
803
804impl ops::IndexMut<ops::RangeFrom<usize>> for ThinString {
805 #[inline]
806 fn index_mut(&mut self, index: ops::RangeFrom<usize>) -> &mut str {
807 &mut self[..][index]
808 }
809}
810
811impl ops::IndexMut<ops::RangeFull> for ThinString {
812 #[inline]
813 fn index_mut(&mut self, _index: ops::RangeFull) -> &mut str {
814 unsafe { from_utf8_unchecked_mut(&mut self.vec) }
815 }
816}
817
818impl ops::IndexMut<ops::RangeInclusive<usize>> for ThinString {
819 #[inline]
820 fn index_mut(&mut self, index: ops::RangeInclusive<usize>) -> &mut str {
821 IndexMut::index_mut(&mut **self, index)
822 }
823}
824
825impl ops::IndexMut<ops::RangeToInclusive<usize>> for ThinString {
826 #[inline]
827 fn index_mut(&mut self, index: ops::RangeToInclusive<usize>) -> &mut str {
828 IndexMut::index_mut(&mut **self, index)
829 }
830}
831
832impl ops::Deref for ThinString {
833 type Target = str;
834
835 #[inline]
836 fn deref(&self) -> &str {
837 unsafe { from_utf8_unchecked(&self.vec) }
838 }
839}
840
841impl ops::DerefMut for ThinString {
842 #[inline]
843 fn deref_mut(&mut self) -> &mut str {
844 unsafe { from_utf8_unchecked_mut(&mut self.vec) }
845 }
846}
847
848pub type ParseError = core::convert::Infallible;
849
850impl FromStr for ThinString {
851 type Err = core::convert::Infallible;
852 #[inline]
853 fn from_str(s: &str) -> Result<ThinString, Self::Err> {
854 Ok(ThinString::from(s))
855 }
856}
857
858impl From<String> for ThinString {
859 #[inline]
860 fn from(string: String) -> ThinString {
861 ThinString::from(string.as_str())
862 }
863}
864
865impl From<ThinString> for String {
866 #[inline]
867 fn from(string: ThinString) -> String {
868 string.to_string()
869 }
870}
871
872pub trait ToThinString {
873 fn to_thin_string(&self) -> ThinString;
874}
875
876#[cfg(not(feature = "nightly"))]
877impl<T: fmt::Display + ?Sized> ToThinString for T {
878 #[inline]
879 fn to_thin_string(&self) -> ThinString {
880 use fmt::Write as _;
881 let mut buf = ThinString::new();
882 write!(&mut buf, "{}", self)
883 .expect("a Display implementation returned an error unexpectedly");
884 buf
885 }
886}
887
888#[cfg(feature = "nightly")]
889impl<T: fmt::Display + ?Sized> ToThinString for T {
890 #[inline]
891 default fn to_thin_string(&self) -> ThinString {
892 let mut buf = ThinString::new();
893 let mut formatter = core::fmt::Formatter::new(&mut buf);
894 fmt::Display::fmt(self, &mut formatter)
896 .expect("a Display implementation returned an error unexpectedly");
897 buf
898 }
899}
900
901#[cfg(feature = "nightly")]
902impl ToThinString for char {
903 #[inline]
904 fn to_thin_string(&self) -> ThinString {
905 ThinString::from(self.encode_utf8(&mut [0; 4]))
906 }
907}
908
909#[cfg(feature = "nightly")]
910impl ToThinString for u8 {
911 #[inline]
912 fn to_thin_string(&self) -> ThinString {
913 let mut buf = ThinString::with_capacity(3);
914 let mut n = *self;
915 if n >= 10 {
916 if n >= 100 {
917 buf.push((b'0' + n / 100) as char);
918 n %= 100;
919 }
920 buf.push((b'0' + n / 10) as char);
921 n %= 10;
922 }
923 buf.push((b'0' + n) as char);
924 buf
925 }
926}
927
928#[cfg(feature = "nightly")]
929impl ToThinString for i8 {
930 #[inline]
931 fn to_thin_string(&self) -> ThinString {
932 let mut buf = ThinString::with_capacity(4);
933 if self.is_negative() {
934 buf.push('-');
935 }
936 let mut n = self.unsigned_abs();
937 if n >= 10 {
938 if n >= 100 {
939 buf.push('1');
940 n -= 100;
941 }
942 buf.push((b'0' + n / 10) as char);
943 n %= 10;
944 }
945 buf.push((b'0' + n) as char);
946 buf
947 }
948}
949
950#[cfg(feature = "nightly")]
951impl ToThinString for str {
952 #[inline]
953 fn to_thin_string(&self) -> ThinString {
954 ThinString::from(self)
955 }
956}
957
958#[cfg(feature = "nightly")]
959impl ToThinString for Cow<'_, str> {
960 #[inline]
961 fn to_thin_string(&self) -> ThinString {
962 self[..].to_thin_string()
963 }
964}
965
966#[cfg(feature = "nightly")]
967impl ToThinString for ThinString {
968 #[inline]
969 fn to_thin_string(&self) -> ThinString {
970 self.to_owned()
971 }
972}
973
974impl AsRef<str> for ThinString {
975 #[inline]
976 fn as_ref(&self) -> &str {
977 self
978 }
979}
980
981impl AsMut<str> for ThinString {
982 #[inline]
983 fn as_mut(&mut self) -> &mut str {
984 self
985 }
986}
987
988impl AsRef<[u8]> for ThinString {
989 #[inline]
990 fn as_ref(&self) -> &[u8] {
991 self.as_bytes()
992 }
993}
994
995impl From<&str> for ThinString {
996 fn from(s: &str) -> ThinString {
997 let mut vec = ThinVec::with_capacity(s.bytes().len());
998 vec.extend_from_slice(s.as_bytes());
999 ThinString { vec }
1000 }
1001}
1002
1003impl From<&mut str> for ThinString {
1004 #[inline]
1005 fn from(s: &mut str) -> ThinString {
1006 let mut vec = ThinVec::with_capacity(s.bytes().len());
1007 vec.extend_from_slice(s.as_bytes());
1008 ThinString { vec }
1009 }
1010}
1011
1012impl From<&ThinString> for ThinString {
1013 #[inline]
1014 fn from(s: &ThinString) -> ThinString {
1015 s.clone()
1016 }
1017}
1018
1019impl<'a> From<Cow<'a, str>> for ThinString {
1020 fn from(s: Cow<'a, str>) -> ThinString {
1021 s.to_thin_string()
1022 }
1023}
1024
1025impl<'a> From<&'a ThinString> for Cow<'a, str> {
1026 #[inline]
1027 fn from(s: &'a ThinString) -> Cow<'a, str> {
1028 Cow::Borrowed(s.as_str())
1029 }
1030}
1031
1032impl From<ThinString> for ThinVec<u8> {
1033 fn from(string: ThinString) -> ThinVec<u8> {
1034 string.into_bytes()
1035 }
1036}
1037
1038impl fmt::Write for ThinString {
1039 #[inline]
1040 fn write_str(&mut self, s: &str) -> fmt::Result {
1041 self.push_str(s);
1042 Ok(())
1043 }
1044
1045 #[inline]
1046 fn write_char(&mut self, c: char) -> fmt::Result {
1047 self.push(c);
1048 Ok(())
1049 }
1050}
1051
1052pub struct Drain<'a> {
1053 string: *mut ThinString,
1055 start: usize,
1057 end: usize,
1059 iter: Chars<'a>,
1061}
1062
1063impl fmt::Debug for Drain<'_> {
1064 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1065 f.debug_tuple("Drain").field(&self.as_str()).finish()
1066 }
1067}
1068
1069unsafe impl Sync for Drain<'_> {}
1070unsafe impl Send for Drain<'_> {}
1071
1072impl Drop for Drain<'_> {
1073 #[inline]
1074 fn drop(&mut self) {
1075 unsafe {
1076 let self_vec = (*self.string).as_mut_vec();
1079 if self.start <= self.end && self.end <= self_vec.len() {
1080 self_vec.drain(self.start..self.end);
1081 }
1082 }
1083 }
1084}
1085
1086impl<'a> Drain<'a> {
1087 #[inline]
1088 pub fn as_str(&self) -> &str {
1089 self.iter.as_str()
1090 }
1091}
1092
1093impl Iterator for Drain<'_> {
1094 type Item = char;
1095
1096 #[inline]
1097 fn next(&mut self) -> Option<char> {
1098 self.iter.next()
1099 }
1100
1101 fn size_hint(&self) -> (usize, Option<usize>) {
1102 self.iter.size_hint()
1103 }
1104
1105 #[inline]
1106 fn last(mut self) -> Option<char> {
1107 self.next_back()
1108 }
1109}
1110
1111impl DoubleEndedIterator for Drain<'_> {
1112 #[inline]
1113 fn next_back(&mut self) -> Option<char> {
1114 self.iter.next_back()
1115 }
1116}
1117
1118impl FusedIterator for Drain<'_> {}
1119
1120impl From<char> for ThinString {
1121 #[inline]
1122 fn from(c: char) -> Self {
1123 c.to_thin_string()
1124 }
1125}
1126
1127#[cfg(feature = "serde")]
1128impl serde::Serialize for ThinString {
1129 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1130 where
1131 S: serde::Serializer,
1132 {
1133 serializer.serialize_str(self.as_str())
1134 }
1135}
1136
1137#[cfg(feature = "serde")]
1138impl<'de> serde::Deserialize<'de> for ThinString {
1139 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1140 where
1141 D: serde::Deserializer<'de>,
1142 {
1143 use serde::de::{Error, Unexpected, Visitor};
1144
1145 struct ThinStringVisitor;
1146
1147 impl<'de> Visitor<'de> for ThinStringVisitor {
1148 type Value = ThinString;
1149
1150 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1151 write!(formatter, "a string")
1152 }
1153
1154 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
1155 where
1156 E: serde::de::Error,
1157 {
1158 Ok(v.into())
1159 }
1160
1161 fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
1162 where
1163 E: serde::de::Error,
1164 {
1165 match from_utf8(v) {
1166 Ok(u) => Ok(u.into()),
1167 Err(_) => Err(Error::invalid_value(Unexpected::Bytes(v), &self)),
1168 }
1169 }
1170 }
1171
1172 deserializer.deserialize_str(ThinStringVisitor)
1173 }
1174}