1#![cfg_attr(not(feature = "alloc"), doc = "
24# WARNING
25The `alloc` feature is disabled. This means that a `TinyString` won't be able to
26grow over it's stack capacity.
27
28The following functions from [TinyString] can cause the program to panic if the string
29exceeds its capacity.
30- [with_capacity]
31- [repeat](TinyString::repeat)
32- [push]
33- [push_str]
34- [reserve]
35- [reserve_exact]
36- [extend_from_within](TinyString::extend_from_within)
37- [insert](TinyString::insert)
38- [insert_str](TinyString::insert_str)
39
40## Alternatives
41| May Panic | No Panic |
42| --------- | -------- |
43| [push] | [push_within_capacity](TinyString::push_within_capacity) |
44| [push_str] | [push_within_capacity](TinyString::push_str_within_capacity) |
45| [reserve] | [try_reserve](TinyString::try_reserve) |
46| [with_capacity] | [try_with_capacity](TinyString::try_with_capacity) |
47| [reserve] | [try_reserve](TinyString::try_reserve) |
48| [reserve_exact] | [try_reserve_exact](TinyString::try_reserve_exact) |
49
50[push]: TinyString::push
51[push_str]: TinyString::push_str
52[reserve]: TinyString::reserve
53[reserve_exact]: TinyString::reserve_exact
54[with_capacity]: TinyString::with_capacity
55")]
56#![cfg_attr(not(feature = "alloc"), doc = "
83[String]: <https://doc.rust-lang.org/alloc/string/struct.String.html>
84[Vec]: <https://doc.rust-lang.org/alloc/vec/struct.Vec.html>")]
85
86#![no_std]
87
88#![cfg_attr(feature = "use-nightly-features", feature(extend_one))]
89
90use core::fmt::{self, Display};
91use core::hash::Hash;
92use core::ops::{AddAssign, Bound, Deref, DerefMut, Range, RangeBounds};
93use core::str::{self, FromStr, Utf8Error};
94
95#[cfg(feature = "alloc")]
96extern crate alloc;
97#[cfg(feature = "alloc")]
98use alloc::{
99 vec::Vec,
100 boxed::Box,
101 string::String,
102};
103
104use tiny_vec::TinyVec;
105pub use tiny_vec::ResizeError;
106pub mod iter;
107
108pub mod drain;
109
110mod cow;
111pub use cow::Cow;
112
113const MAX_N_STACK_ELEMENTS: usize = tiny_vec::n_elements_for_stack::<u8>();
114
115pub struct TinyString<const N: usize = MAX_N_STACK_ELEMENTS> {
117 buf: TinyVec<u8, N>,
118}
119
120impl<const N: usize> TinyString<N> {
121 fn slice_range<R>(&self, range: R, len: usize) -> Range<usize>
122 where
123 R: RangeBounds<usize>
124 {
125 let start = match range.start_bound() {
126 Bound::Included(n) => *n,
127 Bound::Excluded(n) => *n + 1,
128 Bound::Unbounded => 0,
129 };
130
131 let end = match range.end_bound() {
132 Bound::Included(n) => *n + 1,
133 Bound::Excluded(n) => *n,
134 Bound::Unbounded => len,
135 };
136
137 assert!(start <= end);
138 assert!(end <= len);
139 assert!(self.is_char_boundary(start));
140 assert!(self.is_char_boundary(end));
141
142 Range { start, end }
143 }
144}
145
146impl<const N: usize> TinyString<N> {
147
148 #[inline]
150 #[must_use]
151 pub const fn new() -> Self {
152 Self { buf: TinyVec::new() }
153 }
154
155 #[must_use]
157 pub fn with_capacity(cap: usize) -> Self {
158 Self { buf: TinyVec::with_capacity(cap) }
159 }
160
161 pub fn try_with_capacity(cap: usize) -> Result<Self,ResizeError> {
167 Ok(Self { buf: TinyVec::try_with_capacity(cap)? })
168 }
169
170 pub fn from_utf8(utf8: TinyVec<u8, N>) -> Result<Self,Utf8Error> {
175 str::from_utf8(utf8.as_slice())?;
176 Ok(Self { buf: utf8 })
177 }
178
179 #[inline(always)]
184 #[must_use]
185 pub const unsafe fn from_utf8_unchecked(utf8: TinyVec<u8, N>) -> Self {
186 Self { buf: utf8 }
187 }
188
189 #[must_use]
201 pub fn repeat(slice: &str, n: usize) -> Self {
202 Self {
203 buf: TinyVec::repeat(slice.as_bytes(), n)
204 }
205 }
206
207 #[inline]
209 pub const fn len(&self) -> usize { self.buf.len() }
210
211 #[inline]
213 pub const fn is_empty(&self) -> bool { self.buf.is_empty() }
214
215 #[inline]
217 pub const fn capacity(&self) -> usize { self.buf.capacity() }
218
219 #[inline]
238 pub const fn lives_on_stack(&self) -> bool { self.buf.lives_on_stack() }
239
240 #[inline]
242 pub const fn as_str(&self) -> &str {
243 unsafe { str::from_utf8_unchecked(self.buf.as_slice()) }
244 }
245
246 #[inline]
248 pub const fn as_mut_str(&mut self) -> &mut str {
249 unsafe { str::from_utf8_unchecked_mut(self.buf.as_mut_slice()) }
250 }
251
252 #[inline]
256 pub const fn as_ptr(&self) -> *const u8 {
257 self.buf.as_ptr()
258 }
259
260 #[inline]
264 pub const fn as_mut_ptr(&mut self) -> *mut u8 {
265 self.buf.as_mut_ptr()
266 }
267
268 #[inline]
270 pub const fn as_bytes(&self) -> &[u8] {
271 self.buf.as_slice()
272 }
273
274 #[inline]
297 pub const unsafe fn as_mut_bytes(&mut self) -> &mut [u8] {
298 self.buf.as_mut_slice()
299 }
300
301 #[inline]
322 pub const unsafe fn as_mut_vec(&mut self) -> &mut TinyVec<u8, N> {
323 &mut self.buf
324 }
325
326 pub fn push(&mut self, c: char) {
328 let len = c.len_utf8();
329 if len == 1 {
330 self.buf.push(c as u8);
331 } else {
332 let mut buf = [0_u8; 4];
333 c.encode_utf8(&mut buf);
334 self.buf.copy_from_slice(&buf[..len]);
335 }
336 }
337
338 pub fn push_within_capacity(&mut self, c: char) -> Result<(), char> {
344 let len = c.len_utf8();
345 if self.buf.len() + len > self.buf.capacity() {
346 return Err(c)
347 }
348 if len == 1 {
349 unsafe { self.buf.push_unchecked(c as u8) };
350 } else {
351 let mut buf = [0_u8; 4];
352 c.encode_utf8(&mut buf);
353 self.buf.copy_from_slice(&buf[..len]);
354 }
355 Ok(())
356 }
357
358
359 pub fn pop(&mut self) -> Option<char> {
373 let c = self.chars().next_back()?;
374 let new_len = self.len() - c.len_utf8();
375 unsafe {
376 self.buf.set_len(new_len);
377 }
378 Some(c)
379 }
380
381 #[inline]
383 pub fn push_str(&mut self, s: &str) {
384 self.buf.copy_from_slice(s.as_bytes());
385 }
386
387 pub fn push_str_within_capacity<'a>(&mut self, s: &'a str) -> Result<(), &'a str> {
393 if self.buf.len() + s.len() > self.buf.capacity() {
394 Err(s)
395 } else {
396 self.buf.copy_from_slice(s.as_bytes());
397 Ok(())
398 }
399 }
400 #[inline]
423 #[cfg(feature = "alloc")]
424 pub fn shrink_to(&mut self, min_capacity: usize) {
425 self.buf.shrink_to(min_capacity)
426 }
427
428 #[inline]
442 #[cfg(feature = "alloc")]
443 pub fn shrink_to_fit(&mut self) {
444 self.buf.shrink_to_fit();
445 }
446
447 #[inline]
460 pub fn clear(&mut self) {
461 self.buf.clear();
462 }
463
464 #[inline]
466 pub fn reserve(&mut self, n: usize) {
467 self.buf.reserve(n);
468 }
469
470 #[inline]
473 pub fn try_reserve(&mut self, n: usize) -> Result<(), ResizeError> {
474 self.buf.try_reserve(n)
475 }
476
477 #[inline]
479 pub fn reserve_exact(&mut self, n: usize) {
480 self.buf.reserve_exact(n);
481 }
482
483 #[inline]
486 pub fn try_reserve_exact(&mut self, n: usize) -> Result<(), ResizeError> {
487 self.buf.try_reserve_exact(n)
488 }
489
490 #[cfg(feature = "alloc")]
503 #[must_use]
504 pub fn into_boxed_str(self) -> Box<str> {
505 let b = self.buf.into_boxed_slice();
506 unsafe { alloc::str::from_boxed_utf8_unchecked(b) }
507 }
508
509 pub fn extend_from_within<R>(&mut self, range: R)
528 where
529 R: RangeBounds<usize>
530 {
531 let Range { start, end } = self.slice_range(range, self.len());
532 self.buf.extend_from_within_copied(start..end);
533 }
534
535 #[cfg(feature = "alloc")]
558 pub fn leak<'a>(mut self) -> &'a mut str {
559 self.buf.move_to_heap_exact();
560 self.buf.shrink_to_fit_heap_only();
561 unsafe {
562 let bytes = self.buf.leak();
563 str::from_utf8_unchecked_mut(bytes)
564 }
565 }
566
567 #[inline]
588 #[must_use = "use `.truncate()` if you don't need the other half"]
589 pub fn split_off(&mut self, at: usize) -> TinyString<N> {
590 assert!(self.is_char_boundary(at));
591 let other = self.buf.split_off(at);
592 unsafe { TinyString::from_utf8_unchecked(other) }
593 }
594
595 pub fn truncate(&mut self, new_len: usize) {
616 assert!(self.is_char_boundary(new_len));
617 self.buf.truncate(new_len);
618 }
619
620 pub fn insert(&mut self, index: usize, ch: char) {
639 assert!(self.is_char_boundary(index));
640 let mut buf = [0; 4];
641 ch.encode_utf8(&mut buf);
642 let len = ch.len_utf8();
643 self.buf.insert_slice(index, &buf[..len]).unwrap_or_else(|_| {
644 unreachable!("We've checked the index in the assertion above")
645 })
646 }
647
648 pub fn insert_str(&mut self, index: usize, s: &str) {
667 assert!(self.is_char_boundary(index));
668 self.buf.insert_slice(index, s.as_bytes()).unwrap_or_else(|_| {
669 unreachable!("We've checked the index in the assertion above")
670 })
671 }
672}
673
674impl<const N: usize> Default for TinyString<N> {
675 fn default() -> Self {
676 Self::new()
677 }
678}
679
680impl<const N: usize> Deref for TinyString<N> {
681 type Target = str;
682
683 fn deref(&self) -> &Self::Target {
684 self.as_str()
685 }
686}
687
688impl<const N: usize> DerefMut for TinyString<N> {
689 fn deref_mut(&mut self) -> &mut Self::Target {
690 self.as_mut_str()
691 }
692}
693
694impl<const N: usize> From<&str> for TinyString<N> {
695 fn from(value: &str) -> Self {
696 let mut s = Self::with_capacity(value.len());
697 s.push_str(value);
698 s
699 }
700}
701
702impl<const N: usize> TryFrom<&[u8]> for TinyString<N> {
703 type Error = Utf8Error;
704
705 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
706 str::from_utf8(value)?;
707 Ok(unsafe { Self::from_utf8_unchecked(TinyVec::from_slice_copied(value)) })
708 }
709}
710
711impl<const N: usize> TryFrom<TinyVec<u8, N>> for TinyString<N> {
712 type Error = Utf8Error;
713
714 fn try_from(value: TinyVec<u8, N>) -> Result<Self, Self::Error> {
715 Self::from_utf8(value)
716 }
717}
718
719#[cfg(feature = "alloc")]
720impl<const N: usize> TryFrom<Vec<u8>> for TinyString<N> {
721 type Error = Utf8Error;
722
723 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
724 str::from_utf8(value.as_slice())?;
725 Ok(unsafe { Self::from_utf8_unchecked(TinyVec::from_vec(value)) })
726 }
727}
728
729#[cfg(feature = "alloc")]
730impl<const N: usize> From<String> for TinyString<N> {
731 fn from(value: String) -> Self {
732 let vec = Vec::from(value);
733 let vec = TinyVec::<_, N>::from_vec(vec);
734 unsafe { Self::from_utf8_unchecked(vec) }
735 }
736}
737
738impl<const N: usize> From<TinyString<N>> for TinyVec<u8, N> {
739 fn from(value: TinyString<N>) -> Self {
740 value.buf
741 }
742}
743
744#[cfg(feature = "alloc")]
745impl<const N: usize> From<TinyString<N>> for Vec<u8> {
746 fn from(value: TinyString<N>) -> Self {
747 value.buf.into_vec()
748 }
749}
750
751#[cfg(feature = "alloc")]
752impl<const N: usize> From<TinyString<N>> for Box<str> {
753 fn from(value: TinyString<N>) -> Self {
754 value.into_boxed_str()
755 }
756}
757
758#[cfg(feature = "alloc")]
759impl<const N: usize> From<Box<str>> for TinyString<N> {
760 fn from(value: Box<str>) -> Self {
761 let vec = value.as_bytes();
762 let s = TinyVec::from(vec);
763 unsafe { Self::from_utf8_unchecked(s) }
764 }
765}
766
767macro_rules! impl_from_iter {
768 ($( $( { $($tok:tt)* } )? $t:ty),* $(,)?) => {
769 $(
770 impl< $($($tok)*, )? const N: usize> FromIterator<$t> for TinyString<N> {
771 fn from_iter<T: IntoIterator<Item = $t>>(iter: T) -> Self {
772 let mut s = Self::new();
773 s.extend(iter);
774 s
775 }
776 }
777 )*
778 };
779}
780
781impl_from_iter!(
782 char,
783 {'a} &'a char,
784 {'a} &'a str,
785 {'a, const M: usize} Cow<'a, M>
786);
787
788#[cfg(feature = "alloc")]
789impl_from_iter!(Box<str>);
790
791impl<const N: usize> Extend<char> for TinyString<N> {
792 fn extend<T: IntoIterator<Item = char>>(&mut self, iter: T) {
793 let iter = iter.into_iter();
794 let (lower, _) = iter.size_hint();
795 self.reserve(lower);
796 for c in iter {
797 self.push(c);
798 }
799 }
800
801 #[cfg(feature = "use-nightly-features")]
802 #[inline]
803 fn extend_one(&mut self, item: char) {
804 self.push(item);
805 }
806
807 #[cfg(feature = "use-nightly-features")]
808 #[inline]
809 fn extend_reserve(&mut self, additional: usize) {
810 self.reserve(additional);
811 }
812}
813
814impl<'a, const N: usize> Extend<&'a char> for TinyString<N> {
815 fn extend<T: IntoIterator<Item = &'a char>>(&mut self, iter: T) {
816 iter.into_iter().for_each(|slice| self.push(*slice));
817 }
818
819 #[cfg(feature = "use-nightly-features")]
820 #[inline]
821 fn extend_one(&mut self, item: &'a char) {
822 self.push(*item);
823 }
824
825 #[cfg(feature = "use-nightly-features")]
826 #[inline]
827 fn extend_reserve(&mut self, additional: usize) {
828 self.reserve(additional);
829 }
830}
831
832impl<'a, const N: usize> Extend<&'a str> for TinyString<N> {
833 fn extend<T: IntoIterator<Item = &'a str>>(&mut self, iter: T) {
834 iter.into_iter().for_each(|slice| self.push_str(slice));
835 }
836
837 #[cfg(feature = "use-nightly-features")]
838 #[inline]
839 fn extend_one(&mut self, item: &'a str) {
840 self.push_str(item);
841 }
842}
843
844#[cfg(feature = "alloc")]
845impl<const N: usize> Extend<Box<str>> for TinyString<N> {
846 fn extend<T: IntoIterator<Item = Box<str>>>(&mut self, iter: T) {
847 iter.into_iter().for_each(|slice| self.push_str(&slice));
848 }
849
850 #[cfg(feature = "use-nightly-features")]
851 #[inline]
852 fn extend_one(&mut self, item: Box<str>) {
853 self.push_str(&item);
854 }
855}
856
857impl<'a, const N: usize, const M: usize> Extend<Cow<'a, M>> for TinyString<N> {
858 fn extend<T: IntoIterator<Item = Cow<'a, M>>>(&mut self, iter: T) {
859 iter.into_iter().for_each(|slice| self.push_str(&slice));
860 }
861
862 #[cfg(feature = "use-nightly-features")]
863 #[inline]
864 fn extend_one(&mut self, item: Cow<'a, M>) {
865 self.push_str(&item);
866 }
867}
868
869impl<const N: usize, const M: usize> PartialEq<TinyString<M>> for TinyString<N> {
870 fn eq(&self, other: &TinyString<M>) -> bool {
871 self.as_bytes() == other.as_bytes()
872 }
873}
874
875impl<const N: usize> Eq for TinyString<N> { }
876
877impl<'a, const N: usize, const M: usize> PartialEq<Cow<'a, M>> for TinyString<N> {
878 fn eq(&self, other: &Cow<'a, M>) -> bool {
879 self.as_bytes() == other.as_bytes()
880 }
881}
882
883#[cfg(feature = "alloc")]
884impl<const N: usize> PartialEq<String> for TinyString<N> {
885 fn eq(&self, other: &String) -> bool {
886 self.as_bytes() == other.as_bytes()
887 }
888}
889
890impl<const N: usize, const M: usize> PartialEq<TinyVec<u8, M>> for TinyString<N> {
891 fn eq(&self, other: &TinyVec<u8, M>) -> bool {
892 self.as_bytes() == other.as_slice()
893 }
894}
895
896impl<'a, const N: usize, const M: usize> PartialEq<tiny_vec::Cow<'a, u8, M>> for TinyString<N> {
897 fn eq(&self, other: &tiny_vec::Cow<'a, u8, M>) -> bool {
898 self.as_bytes() == other.as_slice()
899 }
900}
901
902#[cfg(feature = "alloc")]
903impl<const N: usize> PartialEq<Vec<u8>> for TinyString<N> {
904 fn eq(&self, other: &Vec<u8>) -> bool {
905 self.as_bytes() == other.as_slice()
906 }
907}
908
909impl<const N: usize> PartialEq<str> for TinyString<N> {
910 fn eq(&self, other: &str) -> bool {
911 self.as_str() == other
912 }
913}
914
915impl<'a, const N: usize> PartialEq<&'a str> for TinyString<N> {
916 fn eq(&self, other: &&'a str) -> bool {
917 self.as_str() == *other
918 }
919}
920
921impl<const N: usize> PartialEq<[u8]> for TinyString<N> {
922 fn eq(&self, other: &[u8]) -> bool {
923 self.as_bytes() == other
924 }
925}
926
927impl<const N: usize> PartialEq<TinyString<N>> for &str {
928 fn eq(&self, other: &TinyString<N>) -> bool {
929 self.as_bytes() == other.as_bytes()
930 }
931}
932
933impl<const N: usize> PartialOrd<TinyString<N>> for TinyString<N> {
934 #[inline]
935 fn partial_cmp(&self, other: &TinyString<N>) -> Option<core::cmp::Ordering> {
936 Some(self.cmp(other))
937 }
938}
939
940impl<const N: usize> Ord for TinyString<N> {
941 #[inline]
942 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
943 self.buf.cmp(&other.buf)
944 }
945}
946
947impl<const N: usize> Clone for TinyString<N> {
948 #[inline]
949 fn clone(&self) -> Self {
950 Self { buf: self.buf.clone() }
951 }
952
953 #[inline]
954 fn clone_from(&mut self, source: &Self) {
955 self.buf.clone_from(&source.buf);
956 }
957}
958
959impl<const N: usize> AsRef<[u8]> for TinyString<N> {
960 #[inline]
961 fn as_ref(&self) -> &[u8] {
962 self.as_bytes()
963 }
964}
965
966impl<const N: usize> AsRef<str> for TinyString<N> {
967 #[inline]
968 fn as_ref(&self) -> &str {
969 self.as_str()
970 }
971}
972
973impl<const N: usize> AsMut<str> for TinyString<N> {
974 #[inline]
975 fn as_mut(&mut self) -> &mut str {
976 self.as_mut_str()
977 }
978}
979
980impl<const N: usize> AsRef<TinyString<N>> for TinyString<N> {
981 #[inline]
982 fn as_ref(&self) -> &TinyString<N> {
983 self
984 }
985}
986
987impl<const N: usize> AsMut<TinyString<N>> for TinyString<N> {
988 #[inline]
989 fn as_mut(&mut self) -> &mut TinyString<N> {
990 self
991 }
992}
993
994impl<const N: usize> Hash for TinyString<N> {
995 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
996 self.buf.hash(state);
997 }
998}
999
1000impl<const N: usize> fmt::Debug for TinyString<N> {
1001 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1002 write!(f, "{:?}", self.bytes())
1003 }
1004}
1005
1006impl<const N: usize> Display for TinyString<N> {
1007 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1008 write!(f, "{}", self.as_str())
1009 }
1010}
1011
1012impl<const N: usize> FromStr for TinyString<N> {
1013 type Err = core::convert::Infallible;
1014
1015 fn from_str(s: &str) -> Result<Self, Self::Err> {
1016 Ok(Self::from(s))
1017 }
1018}
1019
1020impl<const N: usize> core::fmt::Write for TinyString<N> {
1021 fn write_str(&mut self, s: &str) -> fmt::Result {
1022 self.push_str(s);
1023 Ok(())
1024 }
1025
1026 fn write_char(&mut self, c: char) -> fmt::Result {
1027 self.push(c);
1028 Ok(())
1029 }
1030}
1031
1032impl<'a, const N: usize> AddAssign<&'a str> for TinyString<N> {
1033 #[inline]
1034 fn add_assign(&mut self, rhs: &'a str) {
1035 self.push_str(rhs);
1036 }
1037}
1038
1039#[cfg(feature = "serde")]
1040impl<const N: usize> serde::Serialize for TinyString<N> {
1041 #[inline]
1042 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1043 where
1044 S: serde::Serializer
1045 {
1046 self.buf.serialize(serializer)
1047 }
1048}
1049
1050#[cfg(feature = "serde")]
1051impl<'de, const N: usize> serde::Deserialize<'de> for TinyString<N> {
1052 #[inline]
1053 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1054 where
1055 D: serde::Deserializer<'de>
1056 {
1057 let buf = TinyVec::<u8, N>::deserialize(deserializer)?;
1058 Ok(Self { buf })
1059 }
1060}
1061
1062#[cfg(test)]
1063mod test;