1#![deny(unsafe_code)]
100#![forbid(rust_2018_idioms)]
101#![deny(nonstandard_style)]
102#![warn(unreachable_pub, missing_debug_implementations, missing_docs)]
103#![cfg_attr(not(feature = "std"), no_std)]
104#![cfg_attr(needs_allocator_feature, feature(allocator_api))]
105
106extern crate alloc;
107
108use alloc::{
109 boxed::Box,
110 string::{String, ToString},
111};
112use core::{
113 borrow::{Borrow, BorrowMut},
114 cmp::Ordering,
115 convert::Infallible,
116 fmt::{Debug, Display, Error, Formatter, Write},
117 hash::{Hash, Hasher},
118 iter::FromIterator,
119 marker::PhantomData,
120 mem::{forget, MaybeUninit},
121 ops::{
122 Add, Deref, DerefMut, Index, IndexMut, Range, RangeBounds, RangeFrom, RangeFull,
123 RangeInclusive, RangeTo, RangeToInclusive,
124 },
125 ptr::drop_in_place,
126 str::FromStr,
127};
128
129#[cfg(feature = "std")]
130use std::borrow::Cow;
131
132mod config;
133pub use config::{Compact, LazyCompact, SmartStringMode, MAX_INLINE};
134
135mod marker_byte;
136use marker_byte::Discriminant;
137
138mod inline;
139use inline::InlineString;
140
141mod boxed;
142use boxed::BoxedString;
143
144mod casts;
145use casts::{StringCast, StringCastInto, StringCastMut};
146
147mod iter;
148pub use iter::Drain;
149
150mod ops;
151use ops::{string_op_grow, string_op_shrink};
152
153#[cfg(feature = "serde")]
154mod serde;
155
156#[cfg(feature = "arbitrary")]
157mod arbitrary;
158
159#[cfg(feature = "proptest")]
160pub mod proptest;
161
162pub mod alias {
164 use super::*;
165
166 pub type String = SmartString<LazyCompact>;
170
171 pub type CompactString = SmartString<Compact>;
173}
174
175pub struct SmartString<Mode: SmartStringMode> {
192 data: MaybeUninit<InlineString>,
193 mode: PhantomData<Mode>,
194}
195
196impl<Mode: SmartStringMode> Drop for SmartString<Mode> {
197 fn drop(&mut self) {
198 if let StringCastMut::Boxed(string) = self.cast_mut() {
199 #[allow(unsafe_code)]
200 unsafe {
201 drop_in_place(string)
202 };
203 }
204 }
205}
206
207impl<Mode: SmartStringMode> Clone for SmartString<Mode> {
208 fn clone(&self) -> Self {
213 match self.cast() {
214 StringCast::Boxed(string) => Self::from_boxed(string.clone()),
215 StringCast::Inline(string) => Self::from_inline(*string),
216 }
217 }
218}
219
220impl<Mode: SmartStringMode> Deref for SmartString<Mode> {
221 type Target = str;
222
223 #[inline(always)]
224 fn deref(&self) -> &Self::Target {
225 match self.cast() {
226 StringCast::Boxed(string) => string.deref(),
227 StringCast::Inline(string) => string.deref(),
228 }
229 }
230}
231
232impl<Mode: SmartStringMode> DerefMut for SmartString<Mode> {
233 #[inline(always)]
234 fn deref_mut(&mut self) -> &mut Self::Target {
235 match self.cast_mut() {
236 StringCastMut::Boxed(string) => string.deref_mut(),
237 StringCastMut::Inline(string) => string.deref_mut(),
238 }
239 }
240}
241
242impl SmartString<LazyCompact> {
243 pub const fn new_const() -> Self {
250 Self {
251 data: MaybeUninit::new(InlineString::new()),
252 mode: PhantomData,
253 }
254 }
255}
256
257impl SmartString<Compact> {
258 pub const fn new_const() -> Self {
265 Self {
266 data: MaybeUninit::new(InlineString::new()),
267 mode: PhantomData,
268 }
269 }
270}
271
272impl<Mode: SmartStringMode> SmartString<Mode> {
273 #[inline(always)]
275 pub fn new() -> Self {
276 Self::from_inline(InlineString::new())
277 }
278
279 fn from_boxed(boxed: BoxedString) -> Self {
280 let mut out = Self {
281 data: MaybeUninit::uninit(),
282 mode: PhantomData,
283 };
284 let data_ptr: *mut BoxedString = out.data.as_mut_ptr().cast();
285 #[allow(unsafe_code)]
286 unsafe {
287 data_ptr.write(boxed)
288 };
289 out
290 }
291
292 fn from_inline(inline: InlineString) -> Self {
293 Self {
294 data: MaybeUninit::new(inline),
295 mode: PhantomData,
296 }
297 }
298
299 fn discriminant(&self) -> Discriminant {
300 let str_ptr: *const BoxedString =
302 self.data.as_ptr().cast() as *const _ as *const BoxedString;
303 #[allow(unsafe_code)]
304 Discriminant::from_bit(BoxedString::check_alignment(unsafe { &*str_ptr }))
305 }
306
307 fn cast(&self) -> StringCast<'_> {
308 #[allow(unsafe_code)]
309 match self.discriminant() {
310 Discriminant::Inline => StringCast::Inline(unsafe { &*self.data.as_ptr() }),
311 Discriminant::Boxed => StringCast::Boxed(unsafe { &*self.data.as_ptr().cast() }),
312 }
313 }
314
315 fn cast_mut(&mut self) -> StringCastMut<'_> {
316 #[allow(unsafe_code)]
317 match self.discriminant() {
318 Discriminant::Inline => StringCastMut::Inline(unsafe { &mut *self.data.as_mut_ptr() }),
319 Discriminant::Boxed => {
320 StringCastMut::Boxed(unsafe { &mut *self.data.as_mut_ptr().cast() })
321 }
322 }
323 }
324
325 fn cast_into(mut self) -> StringCastInto {
326 #[allow(unsafe_code)]
327 match self.discriminant() {
328 Discriminant::Inline => StringCastInto::Inline(unsafe { self.data.assume_init() }),
329 Discriminant::Boxed => StringCastInto::Boxed(unsafe {
330 let boxed_ptr: *mut BoxedString = self.data.as_mut_ptr().cast();
331 let string = boxed_ptr.read();
332 forget(self);
333 string
334 }),
335 }
336 }
337
338 fn promote_from(&mut self, string: BoxedString) {
339 debug_assert!(self.discriminant() == Discriminant::Inline);
340 let data: *mut BoxedString = self.data.as_mut_ptr().cast();
341 #[allow(unsafe_code)]
342 unsafe {
343 data.write(string)
344 };
345 }
346
347 fn try_demote(&mut self) -> bool {
351 if Mode::DEALLOC {
352 self.really_try_demote()
353 } else {
354 false
355 }
356 }
357
358 fn really_try_demote(&mut self) -> bool {
360 if let StringCastMut::Boxed(string) = self.cast_mut() {
361 if string.len() > MAX_INLINE {
362 false
363 } else {
364 let s: &str = string.deref();
365 let inlined = s.into();
366 #[allow(unsafe_code)]
367 unsafe {
368 drop_in_place(string);
369 self.data.as_mut_ptr().write(inlined);
370 }
371 true
372 }
373 } else {
374 true
375 }
376 }
377
378 pub fn len(&self) -> usize {
382 match self.cast() {
383 StringCast::Boxed(string) => string.len(),
384 StringCast::Inline(string) => string.len(),
385 }
386 }
387
388 pub fn is_empty(&self) -> bool {
390 self.len() == 0
391 }
392
393 pub fn is_inline(&self) -> bool {
395 self.discriminant() == Discriminant::Inline
396 }
397
398 pub fn as_str(&self) -> &str {
400 self.deref()
401 }
402
403 pub fn as_mut_str(&mut self) -> &mut str {
405 self.deref_mut()
406 }
407
408 pub fn capacity(&self) -> usize {
417 if let StringCast::Boxed(string) = self.cast() {
418 string.capacity()
419 } else {
420 MAX_INLINE
421 }
422 }
423
424 pub fn push(&mut self, ch: char) {
426 string_op_grow!(ops::Push, self, ch)
427 }
428
429 pub fn push_str(&mut self, string: &str) {
431 string_op_grow!(ops::PushStr, self, string)
432 }
433
434 pub fn shrink_to_fit(&mut self) {
444 if let StringCastMut::Boxed(string) = self.cast_mut() {
445 if string.len() > MAX_INLINE {
446 string.shrink_to_fit();
447 }
448 }
449 self.really_try_demote();
450 }
451
452 pub fn truncate(&mut self, new_len: usize) {
457 string_op_shrink!(ops::Truncate, self, new_len)
458 }
459
460 pub fn pop(&mut self) -> Option<char> {
462 string_op_shrink!(ops::Pop, self)
463 }
464
465 pub fn remove(&mut self, index: usize) -> char {
469 string_op_shrink!(ops::Remove, self, index)
470 }
471
472 pub fn insert(&mut self, index: usize, ch: char) {
476 string_op_grow!(ops::Insert, self, index, ch)
477 }
478
479 pub fn insert_str(&mut self, index: usize, string: &str) {
483 string_op_grow!(ops::InsertStr, self, index, string)
484 }
485
486 pub fn split_off(&mut self, index: usize) -> Self {
493 string_op_shrink!(ops::SplitOff<Mode>, self, index)
494 }
495
496 pub fn clear(&mut self) {
500 *self = Self::new();
501 }
502
503 pub fn retain<F>(&mut self, f: F)
505 where
506 F: FnMut(char) -> bool,
507 {
508 string_op_shrink!(ops::Retain, self, f)
509 }
510
511 pub fn drain<R>(&mut self, range: R) -> Drain<'_, Mode>
516 where
517 R: RangeBounds<usize>,
518 {
519 Drain::new(self, range)
520 }
521
522 pub fn replace_range<R>(&mut self, range: R, replace_with: &str)
524 where
525 R: RangeBounds<usize>,
526 {
527 string_op_grow!(ops::ReplaceRange, self, &range, replace_with);
528 self.try_demote();
529 }
530}
531
532impl<Mode: SmartStringMode> Default for SmartString<Mode> {
533 fn default() -> Self {
534 Self::new()
535 }
536}
537
538impl<Mode: SmartStringMode> AsRef<str> for SmartString<Mode> {
539 fn as_ref(&self) -> &str {
540 self.deref()
541 }
542}
543
544impl<Mode: SmartStringMode> AsMut<str> for SmartString<Mode> {
545 fn as_mut(&mut self) -> &mut str {
546 self.deref_mut()
547 }
548}
549
550impl<Mode: SmartStringMode> AsRef<[u8]> for SmartString<Mode> {
551 fn as_ref(&self) -> &[u8] {
552 self.deref().as_bytes()
553 }
554}
555
556impl<Mode: SmartStringMode> Borrow<str> for SmartString<Mode> {
557 fn borrow(&self) -> &str {
558 self.deref()
559 }
560}
561
562impl<Mode: SmartStringMode> BorrowMut<str> for SmartString<Mode> {
563 fn borrow_mut(&mut self) -> &mut str {
564 self.deref_mut()
565 }
566}
567
568impl<Mode: SmartStringMode> Index<Range<usize>> for SmartString<Mode> {
569 type Output = str;
570 fn index(&self, index: Range<usize>) -> &Self::Output {
571 &self.deref()[index]
572 }
573}
574
575impl<Mode: SmartStringMode> Index<RangeTo<usize>> for SmartString<Mode> {
576 type Output = str;
577 fn index(&self, index: RangeTo<usize>) -> &Self::Output {
578 &self.deref()[index]
579 }
580}
581
582impl<Mode: SmartStringMode> Index<RangeFrom<usize>> for SmartString<Mode> {
583 type Output = str;
584 fn index(&self, index: RangeFrom<usize>) -> &Self::Output {
585 &self.deref()[index]
586 }
587}
588
589impl<Mode: SmartStringMode> Index<RangeFull> for SmartString<Mode> {
590 type Output = str;
591 fn index(&self, _index: RangeFull) -> &Self::Output {
592 self.deref()
593 }
594}
595
596impl<Mode: SmartStringMode> Index<RangeInclusive<usize>> for SmartString<Mode> {
597 type Output = str;
598 fn index(&self, index: RangeInclusive<usize>) -> &Self::Output {
599 &self.deref()[index]
600 }
601}
602
603impl<Mode: SmartStringMode> Index<RangeToInclusive<usize>> for SmartString<Mode> {
604 type Output = str;
605 fn index(&self, index: RangeToInclusive<usize>) -> &Self::Output {
606 &self.deref()[index]
607 }
608}
609
610impl<Mode: SmartStringMode> IndexMut<Range<usize>> for SmartString<Mode> {
611 fn index_mut(&mut self, index: Range<usize>) -> &mut Self::Output {
612 &mut self.deref_mut()[index]
613 }
614}
615
616impl<Mode: SmartStringMode> IndexMut<RangeTo<usize>> for SmartString<Mode> {
617 fn index_mut(&mut self, index: RangeTo<usize>) -> &mut Self::Output {
618 &mut self.deref_mut()[index]
619 }
620}
621
622impl<Mode: SmartStringMode> IndexMut<RangeFrom<usize>> for SmartString<Mode> {
623 fn index_mut(&mut self, index: RangeFrom<usize>) -> &mut Self::Output {
624 &mut self.deref_mut()[index]
625 }
626}
627
628impl<Mode: SmartStringMode> IndexMut<RangeFull> for SmartString<Mode> {
629 fn index_mut(&mut self, _index: RangeFull) -> &mut Self::Output {
630 self.deref_mut()
631 }
632}
633
634impl<Mode: SmartStringMode> IndexMut<RangeInclusive<usize>> for SmartString<Mode> {
635 fn index_mut(&mut self, index: RangeInclusive<usize>) -> &mut Self::Output {
636 &mut self.deref_mut()[index]
637 }
638}
639
640impl<Mode: SmartStringMode> IndexMut<RangeToInclusive<usize>> for SmartString<Mode> {
641 fn index_mut(&mut self, index: RangeToInclusive<usize>) -> &mut Self::Output {
642 &mut self.deref_mut()[index]
643 }
644}
645
646impl<Mode: SmartStringMode> From<&'_ str> for SmartString<Mode> {
647 fn from(string: &'_ str) -> Self {
648 if string.len() > MAX_INLINE {
649 Self::from_boxed(string.to_string().into())
650 } else {
651 Self::from_inline(string.into())
652 }
653 }
654}
655
656impl<Mode: SmartStringMode> From<&'_ mut str> for SmartString<Mode> {
657 fn from(string: &'_ mut str) -> Self {
658 if string.len() > MAX_INLINE {
659 Self::from_boxed(string.to_string().into())
660 } else {
661 Self::from_inline(string.deref().into())
662 }
663 }
664}
665
666impl<Mode: SmartStringMode> From<&'_ String> for SmartString<Mode> {
667 fn from(string: &'_ String) -> Self {
668 if string.len() > MAX_INLINE {
669 Self::from_boxed(string.clone().into())
670 } else {
671 Self::from_inline(string.deref().into())
672 }
673 }
674}
675
676impl<Mode: SmartStringMode> From<String> for SmartString<Mode> {
677 fn from(string: String) -> Self {
678 if string.len() > MAX_INLINE {
679 Self::from_boxed(string.into())
680 } else {
681 Self::from_inline(string.deref().into())
682 }
683 }
684}
685
686impl<Mode: SmartStringMode> From<Box<str>> for SmartString<Mode> {
687 fn from(string: Box<str>) -> Self {
688 if string.len() > MAX_INLINE {
689 String::from(string).into()
690 } else {
691 Self::from(&*string)
692 }
693 }
694}
695
696#[cfg(feature = "std")]
697impl<Mode: SmartStringMode> From<Cow<'_, str>> for SmartString<Mode> {
698 fn from(string: Cow<'_, str>) -> Self {
699 if string.len() > MAX_INLINE {
700 String::from(string).into()
701 } else {
702 Self::from(&*string)
703 }
704 }
705}
706
707impl<'a, Mode: SmartStringMode> Extend<&'a str> for SmartString<Mode> {
708 fn extend<I: IntoIterator<Item = &'a str>>(&mut self, iter: I) {
709 for item in iter {
710 self.push_str(item);
711 }
712 }
713}
714
715impl<'a, Mode: SmartStringMode> Extend<&'a char> for SmartString<Mode> {
716 fn extend<I: IntoIterator<Item = &'a char>>(&mut self, iter: I) {
717 for item in iter {
718 self.push(*item);
719 }
720 }
721}
722
723impl<Mode: SmartStringMode> Extend<char> for SmartString<Mode> {
724 fn extend<I: IntoIterator<Item = char>>(&mut self, iter: I) {
725 for item in iter {
726 self.push(item);
727 }
728 }
729}
730
731impl<Mode: SmartStringMode> Extend<SmartString<Mode>> for SmartString<Mode> {
732 fn extend<I: IntoIterator<Item = SmartString<Mode>>>(&mut self, iter: I) {
733 for item in iter {
734 self.push_str(&item);
735 }
736 }
737}
738
739impl<Mode: SmartStringMode> Extend<String> for SmartString<Mode> {
740 fn extend<I: IntoIterator<Item = String>>(&mut self, iter: I) {
741 for item in iter {
742 self.push_str(&item);
743 }
744 }
745}
746
747impl<'a, Mode: SmartStringMode + 'a> Extend<&'a SmartString<Mode>> for SmartString<Mode> {
748 fn extend<I: IntoIterator<Item = &'a SmartString<Mode>>>(&mut self, iter: I) {
749 for item in iter {
750 self.push_str(item);
751 }
752 }
753}
754
755impl<'a, Mode: SmartStringMode> Extend<&'a String> for SmartString<Mode> {
756 fn extend<I: IntoIterator<Item = &'a String>>(&mut self, iter: I) {
757 for item in iter {
758 self.push_str(item);
759 }
760 }
761}
762
763impl<Mode: SmartStringMode> Add<Self> for SmartString<Mode> {
764 type Output = Self;
765 fn add(mut self, rhs: Self) -> Self::Output {
766 self.push_str(&rhs);
767 self
768 }
769}
770
771impl<Mode: SmartStringMode> Add<&'_ Self> for SmartString<Mode> {
772 type Output = Self;
773 fn add(mut self, rhs: &'_ Self) -> Self::Output {
774 self.push_str(rhs);
775 self
776 }
777}
778
779impl<Mode: SmartStringMode> Add<&'_ str> for SmartString<Mode> {
780 type Output = Self;
781 fn add(mut self, rhs: &'_ str) -> Self::Output {
782 self.push_str(rhs);
783 self
784 }
785}
786
787impl<Mode: SmartStringMode> Add<&'_ String> for SmartString<Mode> {
788 type Output = Self;
789 fn add(mut self, rhs: &'_ String) -> Self::Output {
790 self.push_str(rhs);
791 self
792 }
793}
794
795impl<Mode: SmartStringMode> Add<String> for SmartString<Mode> {
796 type Output = Self;
797 fn add(mut self, rhs: String) -> Self::Output {
798 self.push_str(&rhs);
799 self
800 }
801}
802
803impl<Mode: SmartStringMode> Add<SmartString<Mode>> for String {
804 type Output = Self;
805 fn add(mut self, rhs: SmartString<Mode>) -> Self::Output {
806 self.push_str(&rhs);
807 self
808 }
809}
810
811impl<Mode: SmartStringMode> FromIterator<Self> for SmartString<Mode> {
812 fn from_iter<I: IntoIterator<Item = Self>>(iter: I) -> Self {
813 let mut out = Self::new();
814 out.extend(iter.into_iter());
815 out
816 }
817}
818
819impl<Mode: SmartStringMode> FromIterator<String> for SmartString<Mode> {
820 fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> Self {
821 let mut out = Self::new();
822 out.extend(iter.into_iter());
823 out
824 }
825}
826
827impl<'a, Mode: SmartStringMode + 'a> FromIterator<&'a Self> for SmartString<Mode> {
828 fn from_iter<I: IntoIterator<Item = &'a Self>>(iter: I) -> Self {
829 let mut out = Self::new();
830 out.extend(iter.into_iter());
831 out
832 }
833}
834
835impl<'a, Mode: SmartStringMode> FromIterator<&'a str> for SmartString<Mode> {
836 fn from_iter<I: IntoIterator<Item = &'a str>>(iter: I) -> Self {
837 let mut out = Self::new();
838 out.extend(iter.into_iter());
839 out
840 }
841}
842
843impl<'a, Mode: SmartStringMode> FromIterator<&'a String> for SmartString<Mode> {
844 fn from_iter<I: IntoIterator<Item = &'a String>>(iter: I) -> Self {
845 let mut out = Self::new();
846 out.extend(iter.into_iter());
847 out
848 }
849}
850
851impl<Mode: SmartStringMode> FromIterator<char> for SmartString<Mode> {
852 fn from_iter<I: IntoIterator<Item = char>>(iter: I) -> Self {
853 let mut out = Self::new();
854 for ch in iter {
855 out.push(ch);
856 }
857 out
858 }
859}
860
861impl<Mode: SmartStringMode> FromStr for SmartString<Mode> {
862 type Err = Infallible;
863 fn from_str(s: &str) -> Result<Self, Self::Err> {
864 Ok(Self::from(s))
865 }
866}
867
868impl<Mode: SmartStringMode> From<SmartString<Mode>> for String {
869 fn from(s: SmartString<Mode>) -> Self {
873 match s.cast_into() {
874 StringCastInto::Boxed(string) => string.into(),
875 StringCastInto::Inline(string) => string.to_string(),
876 }
877 }
878}
879
880impl<Mode: SmartStringMode> PartialEq<str> for SmartString<Mode> {
881 fn eq(&self, other: &str) -> bool {
882 self.as_str() == other
883 }
884}
885
886impl<Mode: SmartStringMode> PartialEq<&'_ str> for SmartString<Mode> {
887 fn eq(&self, other: &&str) -> bool {
888 self.as_str() == *other
889 }
890}
891
892impl<Mode: SmartStringMode> PartialEq<SmartString<Mode>> for &'_ str {
893 fn eq(&self, other: &SmartString<Mode>) -> bool {
894 other.eq(*self)
895 }
896}
897
898impl<Mode: SmartStringMode> PartialEq<SmartString<Mode>> for str {
899 fn eq(&self, other: &SmartString<Mode>) -> bool {
900 other.eq(self)
901 }
902}
903
904impl<Mode: SmartStringMode> PartialEq<String> for SmartString<Mode> {
905 fn eq(&self, other: &String) -> bool {
906 self.eq(other.as_str())
907 }
908}
909
910impl<Mode: SmartStringMode> PartialEq<SmartString<Mode>> for String {
911 fn eq(&self, other: &SmartString<Mode>) -> bool {
912 other.eq(self.as_str())
913 }
914}
915
916impl<Mode: SmartStringMode> PartialEq for SmartString<Mode> {
917 fn eq(&self, other: &Self) -> bool {
918 self.as_str() == other.as_str()
919 }
920}
921
922impl<Mode: SmartStringMode> Eq for SmartString<Mode> {}
923
924impl<Mode: SmartStringMode> PartialOrd<str> for SmartString<Mode> {
925 fn partial_cmp(&self, other: &str) -> Option<Ordering> {
926 self.as_str().partial_cmp(other)
927 }
928}
929
930impl<Mode: SmartStringMode> PartialOrd for SmartString<Mode> {
931 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
932 self.partial_cmp(other.as_str())
933 }
934}
935
936impl<Mode: SmartStringMode> Ord for SmartString<Mode> {
937 fn cmp(&self, other: &Self) -> Ordering {
938 self.as_str().cmp(other.as_str())
939 }
940}
941
942impl<Mode: SmartStringMode> Hash for SmartString<Mode> {
943 fn hash<H: Hasher>(&self, state: &mut H) {
944 self.as_str().hash(state)
945 }
946}
947
948impl<Mode: SmartStringMode> Debug for SmartString<Mode> {
949 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
950 Debug::fmt(self.as_str(), f)
951 }
952}
953
954impl<Mode: SmartStringMode> Display for SmartString<Mode> {
955 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
956 Display::fmt(self.as_str(), f)
957 }
958}
959
960impl<Mode: SmartStringMode> Write for SmartString<Mode> {
961 fn write_str(&mut self, string: &str) -> Result<(), Error> {
962 self.push_str(string);
963 Ok(())
964 }
965}
966
967#[cfg(any(test, feature = "test"))]
968#[allow(missing_docs)]
969pub mod test;