@@ -34,13 +34,17 @@ use core::{
3434pub struct SmolStr ( Repr ) ;
3535
3636impl SmolStr {
37+ /// The maximum byte length of a string that can be stored inline
38+ /// without heap allocation.
39+ pub const INLINE_CAP : usize = INLINE_CAP ;
40+
3741 /// Constructs an inline variant of `SmolStr`.
3842 ///
3943 /// This never allocates.
4044 ///
4145 /// # Panics
4246 ///
43- /// Panics if `text.len() > 23` .
47+ /// Panics if `text.len() > `[`SmolStr::INLINE_CAP`] .
4448 #[ inline]
4549 pub const fn new_inline ( text : & str ) -> SmolStr {
4650 assert ! ( text. len( ) <= INLINE_CAP ) ; // avoids bounds checks in loop
@@ -241,6 +245,48 @@ impl PartialOrd for SmolStr {
241245 }
242246}
243247
248+ impl PartialOrd < str > for SmolStr {
249+ fn partial_cmp ( & self , other : & str ) -> Option < Ordering > {
250+ Some ( self . as_str ( ) . cmp ( other) )
251+ }
252+ }
253+
254+ impl < ' a > PartialOrd < & ' a str > for SmolStr {
255+ fn partial_cmp ( & self , other : & & ' a str ) -> Option < Ordering > {
256+ Some ( self . as_str ( ) . cmp ( * other) )
257+ }
258+ }
259+
260+ impl PartialOrd < SmolStr > for & str {
261+ fn partial_cmp ( & self , other : & SmolStr ) -> Option < Ordering > {
262+ Some ( ( * self ) . cmp ( other. as_str ( ) ) )
263+ }
264+ }
265+
266+ impl PartialOrd < String > for SmolStr {
267+ fn partial_cmp ( & self , other : & String ) -> Option < Ordering > {
268+ Some ( self . as_str ( ) . cmp ( other. as_str ( ) ) )
269+ }
270+ }
271+
272+ impl PartialOrd < SmolStr > for String {
273+ fn partial_cmp ( & self , other : & SmolStr ) -> Option < Ordering > {
274+ Some ( self . as_str ( ) . cmp ( other. as_str ( ) ) )
275+ }
276+ }
277+
278+ impl < ' a > PartialOrd < & ' a String > for SmolStr {
279+ fn partial_cmp ( & self , other : & & ' a String ) -> Option < Ordering > {
280+ Some ( self . as_str ( ) . cmp ( other. as_str ( ) ) )
281+ }
282+ }
283+
284+ impl PartialOrd < SmolStr > for & String {
285+ fn partial_cmp ( & self , other : & SmolStr ) -> Option < Ordering > {
286+ Some ( self . as_str ( ) . cmp ( other. as_str ( ) ) )
287+ }
288+ }
289+
244290impl hash:: Hash for SmolStr {
245291 fn hash < H : hash:: Hasher > ( & self , hasher : & mut H ) {
246292 self . as_str ( ) . hash ( hasher) ;
@@ -385,6 +431,20 @@ impl AsRef<std::path::Path> for SmolStr {
385431 }
386432}
387433
434+ impl From < char > for SmolStr {
435+ #[ inline]
436+ fn from ( c : char ) -> SmolStr {
437+ let mut buf = [ 0 ; INLINE_CAP ] ;
438+ let len = c. len_utf8 ( ) ;
439+ c. encode_utf8 ( & mut buf) ;
440+ SmolStr ( Repr :: Inline {
441+ // SAFETY: A char is at most 4 bytes, which is always <= INLINE_CAP (23).
442+ len : unsafe { InlineSize :: transmute_from_u8 ( len as u8 ) } ,
443+ buf,
444+ } )
445+ }
446+ }
447+
388448impl From < & str > for SmolStr {
389449 #[ inline]
390450 fn from ( s : & str ) -> SmolStr {
@@ -888,10 +948,18 @@ macro_rules! format_smolstr {
888948/// A builder that can be used to efficiently build a [`SmolStr`].
889949///
890950/// This won't allocate if the final string fits into the inline buffer.
891- #[ derive( Clone , Default , Debug , PartialEq , Eq ) ]
951+ #[ derive( Clone , Default , Debug ) ]
892952pub struct SmolStrBuilder ( SmolStrBuilderRepr ) ;
893953
894- #[ derive( Clone , Debug , PartialEq , Eq ) ]
954+ impl PartialEq for SmolStrBuilder {
955+ fn eq ( & self , other : & Self ) -> bool {
956+ self . as_str ( ) == other. as_str ( )
957+ }
958+ }
959+
960+ impl Eq for SmolStrBuilder { }
961+
962+ #[ derive( Clone , Debug ) ]
895963enum SmolStrBuilderRepr {
896964 Inline { len : usize , buf : [ u8 ; INLINE_CAP ] } ,
897965 Heap ( String ) ,
@@ -911,6 +979,52 @@ impl SmolStrBuilder {
911979 Self ( SmolStrBuilderRepr :: Inline { buf : [ 0 ; INLINE_CAP ] , len : 0 } )
912980 }
913981
982+ /// Creates a new empty [`SmolStrBuilder`] with at least the specified capacity.
983+ ///
984+ /// If `capacity` is less than or equal to [`SmolStr::INLINE_CAP`], the builder
985+ /// will use inline storage and not allocate. Otherwise, it will pre-allocate a
986+ /// heap buffer of the requested capacity.
987+ #[ must_use]
988+ pub fn with_capacity ( capacity : usize ) -> Self {
989+ if capacity <= INLINE_CAP {
990+ Self :: new ( )
991+ } else {
992+ Self ( SmolStrBuilderRepr :: Heap ( String :: with_capacity ( capacity) ) )
993+ }
994+ }
995+
996+ /// Returns the number of bytes accumulated in the builder so far.
997+ #[ inline]
998+ pub fn len ( & self ) -> usize {
999+ match & self . 0 {
1000+ SmolStrBuilderRepr :: Inline { len, .. } => * len,
1001+ SmolStrBuilderRepr :: Heap ( heap) => heap. len ( ) ,
1002+ }
1003+ }
1004+
1005+ /// Returns `true` if the builder has a length of zero bytes.
1006+ #[ inline]
1007+ pub fn is_empty ( & self ) -> bool {
1008+ match & self . 0 {
1009+ SmolStrBuilderRepr :: Inline { len, .. } => * len == 0 ,
1010+ SmolStrBuilderRepr :: Heap ( heap) => heap. is_empty ( ) ,
1011+ }
1012+ }
1013+
1014+ /// Returns a `&str` slice of the builder's current contents.
1015+ #[ inline]
1016+ pub fn as_str ( & self ) -> & str {
1017+ match & self . 0 {
1018+ SmolStrBuilderRepr :: Inline { len, buf } => {
1019+ // SAFETY: `buf[..*len]` was built by prior `push`/`push_str` calls
1020+ // that only wrote valid UTF-8, and `*len <= INLINE_CAP` is maintained
1021+ // by the inline branch logic.
1022+ unsafe { core:: str:: from_utf8_unchecked ( & buf[ ..* len] ) }
1023+ }
1024+ SmolStrBuilderRepr :: Heap ( heap) => heap. as_str ( ) ,
1025+ }
1026+ }
1027+
9141028 /// Builds a [`SmolStr`] from `self`.
9151029 #[ must_use]
9161030 pub fn finish ( self ) -> SmolStr {
0 commit comments