smallstr/
string.rs

1use core::{
2    borrow::{Borrow, BorrowMut},
3    cmp::Ordering,
4    convert::Infallible,
5    fmt,
6    hash::{Hash, Hasher},
7    iter::{FromIterator, FusedIterator},
8    ops, ptr, slice,
9    str::{self, Chars, Utf8Error},
10};
11
12use alloc::{borrow::Cow, boxed::Box, str::FromStr, string::String};
13
14#[cfg(feature = "ffi")]
15use std::ffi::{OsStr, OsString};
16
17#[cfg(feature = "serde")]
18use core::marker::PhantomData;
19#[cfg(feature = "serde")]
20use serde::{
21    de::{Deserialize, Deserializer, Error, Visitor},
22    ser::{Serialize, Serializer},
23};
24
25use smallvec::{Array, SmallVec};
26
27/// A `String`-like container that can store a small number of bytes inline.
28///
29/// `SmallString` uses a `SmallVec<[u8; N]>` as its internal storage.
30#[derive(Clone, Default)]
31pub struct SmallString<A: Array<Item = u8>> {
32    data: SmallVec<A>,
33}
34
35impl<A: Array<Item = u8>> SmallString<A> {
36    /// Construct an empty string.
37    #[inline]
38    pub fn new() -> SmallString<A> {
39        SmallString {
40            data: SmallVec::new(),
41        }
42    }
43
44    /// Construct an empty string with enough capacity pre-allocated to store
45    /// at least `n` bytes.
46    ///
47    /// Will create a heap allocation only if `n` is larger than the inline capacity.
48    #[inline]
49    pub fn with_capacity(n: usize) -> SmallString<A> {
50        SmallString {
51            data: SmallVec::with_capacity(n),
52        }
53    }
54
55    /// Construct a `SmallString` by copying data from a `&str`.
56    #[allow(clippy::should_implement_trait)]
57    #[inline]
58    pub fn from_str(s: &str) -> SmallString<A> {
59        SmallString {
60            data: SmallVec::from_slice(s.as_bytes()),
61        }
62    }
63
64    /// Construct a `SmallString` by using an existing allocation.
65    #[inline]
66    pub fn from_string(s: String) -> SmallString<A> {
67        SmallString {
68            data: SmallVec::from_vec(s.into_bytes()),
69        }
70    }
71
72    /// Constructs a new `SmallString` on the stack using UTF-8 bytes.
73    ///
74    /// If the provided byte array is not valid UTF-8, an error is returned.
75    #[inline]
76    pub fn from_buf(buf: A) -> Result<SmallString<A>, FromUtf8Error<A>> {
77        let data = SmallVec::from_buf(buf);
78
79        match str::from_utf8(&data) {
80            Ok(_) => Ok(SmallString { data }),
81            Err(error) => {
82                let buf = data.into_inner().ok().unwrap();
83
84                Err(FromUtf8Error { buf, error })
85            }
86        }
87    }
88
89    /// Constructs a new `SmallString` on the stack using the provided byte array
90    /// without checking that the array contains valid UTF-8.
91    ///
92    /// # Safety
93    ///
94    /// This function is unsafe because it does not check that the bytes passed
95    /// to it are valid UTF-8. If this constraint is violated, it may cause
96    /// memory unsafety issues, as the Rust standard library functions assume
97    /// that `&str`s are valid UTF-8.
98    #[inline]
99    pub unsafe fn from_buf_unchecked(buf: A) -> SmallString<A> {
100        SmallString {
101            data: SmallVec::from_buf(buf),
102        }
103    }
104
105    /// The maximum number of bytes this string can hold inline.
106    #[inline]
107    pub fn inline_size(&self) -> usize {
108        A::size()
109    }
110
111    /// Returns the length of this string, in bytes.
112    #[inline]
113    pub fn len(&self) -> usize {
114        self.data.len()
115    }
116
117    /// Returns `true` if this string is empty.
118    #[inline]
119    pub fn is_empty(&self) -> bool {
120        self.data.is_empty()
121    }
122
123    /// Returns the number of bytes this string can hold without reallocating.
124    #[inline]
125    pub fn capacity(&self) -> usize {
126        self.data.capacity()
127    }
128
129    /// Returns `true` if the data has spilled into a separate heap-allocated buffer.
130    #[inline]
131    pub fn spilled(&self) -> bool {
132        self.data.spilled()
133    }
134
135    /// Empties the string and returns an iterator over its former contents.
136    pub fn drain(&mut self) -> Drain<'_> {
137        unsafe {
138            let len = self.len();
139
140            self.data.set_len(0);
141
142            let ptr = self.as_ptr();
143
144            let slice = slice::from_raw_parts(ptr, len);
145            let s = str::from_utf8_unchecked(slice);
146
147            Drain { iter: s.chars() }
148        }
149    }
150
151    /// Empties the sub string and returns an iterator over its former contents.
152    ///
153    /// # Examples
154    ///
155    /// ```
156    /// use smallstr::SmallString;
157    ///
158    /// let mut s: SmallString<[u8; 8]> = SmallString::from("foo bar");
159    /// let sub: String = s.drain_range(1..5).collect();
160    ///
161    /// assert_eq!(sub, "oo b");
162    /// assert_eq!(s, "far");
163    /// ```
164    #[doc(alias = "drain")]
165    pub fn drain_range<R>(&mut self, range: R) -> DrainRange<'_, A>
166    where
167        R: ops::RangeBounds<usize>,
168    {
169        DrainRange {
170            drain: self.data.drain(range),
171        }
172    }
173
174    /// Appends the given `char` to the end of this string.
175    ///
176    /// # Examples
177    ///
178    /// ```
179    /// use smallstr::SmallString;
180    ///
181    /// let mut s: SmallString<[u8; 8]> = SmallString::from("foo");
182    ///
183    /// s.push('x');
184    ///
185    /// assert_eq!(s, "foox");
186    /// ```
187    #[inline]
188    pub fn push(&mut self, ch: char) {
189        match ch.len_utf8() {
190            1 => self.data.push(ch as u8),
191            _ => self.push_str(ch.encode_utf8(&mut [0; 4])),
192        }
193    }
194
195    /// Appends the given string slice to the end of this string.
196    ///
197    /// # Examples
198    ///
199    /// ```
200    /// use smallstr::SmallString;
201    ///
202    /// let mut s: SmallString<[u8; 8]> = SmallString::from("foo");
203    ///
204    /// s.push_str("bar");
205    ///
206    /// assert_eq!(s, "foobar");
207    /// ```
208    #[inline]
209    pub fn push_str(&mut self, s: &str) {
210        self.data.extend_from_slice(s.as_bytes());
211    }
212
213    /// Removes the last character from this string and returns it.
214    ///
215    /// Returns `None` if the string is empty.
216    #[inline]
217    pub fn pop(&mut self) -> Option<char> {
218        match self.chars().next_back() {
219            Some(ch) => unsafe {
220                let new_len = self.len() - ch.len_utf8();
221                self.data.set_len(new_len);
222                Some(ch)
223            },
224            None => None,
225        }
226    }
227
228    /// Reallocates to set the new capacity to `new_cap`.
229    ///
230    /// # Panics
231    ///
232    /// If `new_cap` is less than the current length.
233    #[inline]
234    pub fn grow(&mut self, new_cap: usize) {
235        self.data.grow(new_cap);
236    }
237
238    /// Ensures that this string's capacity is at least `additional` bytes larger
239    /// than its length.
240    ///
241    /// The capacity may be increased by more than `additional` bytes in order to
242    /// prevent frequent reallocations.
243    #[inline]
244    pub fn reserve(&mut self, additional: usize) {
245        self.data.reserve(additional);
246    }
247
248    /// Ensures that this string's capacity is `additional` bytes larger than
249    /// its length.
250    #[inline]
251    pub fn reserve_exact(&mut self, additional: usize) {
252        self.data.reserve(additional);
253    }
254
255    /// Shrink the capacity of the string as much as possible.
256    ///
257    /// When possible, this will move the data from an external heap buffer
258    /// to the string's inline storage.
259    #[inline]
260    pub fn shrink_to_fit(&mut self) {
261        self.data.shrink_to_fit();
262    }
263
264    /// Shorten the string, keeping the first `len` bytes.
265    ///
266    /// This does not reallocate. If you want to shrink the string's capacity,
267    /// use `shrink_to_fit` after truncating.
268    ///
269    /// # Panics
270    ///
271    /// If `len` does not lie on a `char` boundary.
272    #[inline]
273    pub fn truncate(&mut self, len: usize) {
274        assert!(self.is_char_boundary(len));
275        self.data.truncate(len);
276    }
277
278    /// Extracts a string slice containing the entire string.
279    #[inline]
280    pub fn as_str(&self) -> &str {
281        self
282    }
283
284    /// Extracts a string slice containing the entire string.
285    #[inline]
286    pub fn as_mut_str(&mut self) -> &mut str {
287        self
288    }
289
290    /// Removes all contents of the string.
291    #[inline]
292    pub fn clear(&mut self) {
293        self.data.clear();
294    }
295
296    /// Removes a `char` from this string at a byte position and returns it.
297    ///
298    /// # Panics
299    ///
300    /// If `idx` does not lie on a `char` boundary.
301    #[inline]
302    pub fn remove(&mut self, idx: usize) -> char {
303        let ch = match self[idx..].chars().next() {
304            Some(ch) => ch,
305            None => panic!("cannot remove a char from the end of a string"),
306        };
307
308        let ch_len = ch.len_utf8();
309        let next = idx + ch_len;
310        let len = self.len();
311
312        unsafe {
313            let ptr = self.as_mut_ptr();
314
315            ptr::copy(ptr.add(next), ptr.add(idx), len - next);
316            self.data.set_len(len - ch_len);
317        }
318
319        ch
320    }
321
322    /// Inserts a `char` into this string at the given byte position.
323    ///
324    /// # Panics
325    ///
326    /// If `idx` does not lie on `char` boundaries.
327    #[inline]
328    pub fn insert(&mut self, idx: usize, ch: char) {
329        assert!(self.is_char_boundary(idx));
330
331        match ch.len_utf8() {
332            1 => self.data.insert(idx, ch as u8),
333            _ => self.insert_str(idx, ch.encode_utf8(&mut [0; 4])),
334        }
335    }
336
337    /// Inserts a `&str` into this string at the given byte position.
338    ///
339    /// # Panics
340    ///
341    /// If `idx` does not lie on `char` boundaries.
342    #[inline]
343    pub fn insert_str(&mut self, idx: usize, s: &str) {
344        assert!(self.is_char_boundary(idx));
345
346        let len = self.len();
347        let amt = s.len();
348
349        self.data.reserve(amt);
350
351        let ptr = self.as_mut_ptr();
352
353        unsafe {
354            ptr::copy(ptr.add(idx), ptr.add(idx + amt), len - idx);
355            ptr::copy_nonoverlapping(s.as_ptr(), ptr.add(idx), amt);
356            self.data.set_len(len + amt);
357        }
358    }
359
360    /// Returns a mutable reference to the contents of the `SmallString`.
361    ///
362    /// # Safety
363    ///
364    /// This function is unsafe because it does not check that the bytes passed
365    /// to it are valid UTF-8. If this constraint is violated, it may cause
366    /// memory unsafety issues, as the Rust standard library functions assume
367    /// that `&str`s are valid UTF-8.
368    #[inline]
369    pub unsafe fn as_mut_vec(&mut self) -> &mut SmallVec<A> {
370        &mut self.data
371    }
372
373    /// Converts the `SmallString` into a `String`, without reallocating if the
374    /// `SmallString` has already spilled onto the heap.
375    #[inline]
376    pub fn into_string(self) -> String {
377        unsafe { String::from_utf8_unchecked(self.data.into_vec()) }
378    }
379
380    /// Converts the `SmallString` into a `Box<str>`, without reallocating if the
381    /// `SmallString` has already spilled onto the heap.
382    ///
383    /// Note that this will drop excess capacity.
384    #[inline]
385    pub fn into_boxed_str(self) -> Box<str> {
386        self.into_string().into_boxed_str()
387    }
388
389    /// Convert the `SmallString` into `A`, if possible. Otherwise, return `Err(self)`.
390    ///
391    /// This method returns `Err(self)` if the `SmallString` is too short
392    /// (and the `A` contains uninitialized elements) or if the `SmallString` is too long
393    /// (and the elements have been spilled to the heap).
394    #[inline]
395    pub fn into_inner(self) -> Result<A, Self> {
396        self.data.into_inner().map_err(|data| SmallString { data })
397    }
398
399    /// Retains only the characters specified by the predicate.
400    ///
401    /// In other words, removes all characters `c` such that `f(c)` returns `false`.
402    /// This method operates in place and preserves the order of retained
403    /// characters.
404    ///
405    /// # Examples
406    ///
407    /// ```
408    /// use smallstr::SmallString;
409    ///
410    /// let mut s: SmallString<[u8; 16]> = SmallString::from("f_o_ob_ar");
411    ///
412    /// s.retain(|c| c != '_');
413    ///
414    /// assert_eq!(s, "foobar");
415    /// ```
416    #[inline]
417    pub fn retain<F: FnMut(char) -> bool>(&mut self, mut f: F) {
418        struct SetLenOnDrop<'a, A: Array<Item = u8>> {
419            s: &'a mut SmallString<A>,
420            idx: usize,
421            del_bytes: usize,
422        }
423
424        impl<'a, A: Array<Item = u8>> Drop for SetLenOnDrop<'a, A> {
425            fn drop(&mut self) {
426                let new_len = self.idx - self.del_bytes;
427                debug_assert!(new_len <= self.s.len());
428                unsafe { self.s.data.set_len(new_len) };
429            }
430        }
431
432        let len = self.len();
433        let mut guard = SetLenOnDrop {
434            s: self,
435            idx: 0,
436            del_bytes: 0,
437        };
438
439        while guard.idx < len {
440            let ch = unsafe {
441                guard
442                    .s
443                    .get_unchecked(guard.idx..len)
444                    .chars()
445                    .next()
446                    .unwrap()
447            };
448            let ch_len = ch.len_utf8();
449
450            if !f(ch) {
451                guard.del_bytes += ch_len;
452            } else if guard.del_bytes > 0 {
453                let ptr = guard.s.as_mut_ptr();
454
455                unsafe {
456                    ptr::copy(
457                        ptr.add(guard.idx),
458                        ptr.add(guard.idx - guard.del_bytes),
459                        ch_len,
460                    );
461                }
462            }
463
464            // Point idx to the next char
465            guard.idx += ch_len;
466        }
467
468        drop(guard);
469    }
470
471    fn as_ptr(&mut self) -> *const u8 {
472        self.data.as_ptr()
473    }
474
475    fn as_mut_ptr(&mut self) -> *mut u8 {
476        self.data.as_mut_ptr()
477    }
478}
479
480impl<A: Array<Item = u8>> ops::Deref for SmallString<A> {
481    type Target = str;
482
483    #[inline]
484    fn deref(&self) -> &str {
485        let bytes: &[u8] = &self.data;
486        unsafe { str::from_utf8_unchecked(bytes) }
487    }
488}
489
490impl<A: Array<Item = u8>> ops::DerefMut for SmallString<A> {
491    #[inline]
492    fn deref_mut(&mut self) -> &mut str {
493        let bytes: &mut [u8] = &mut self.data;
494        unsafe { str::from_utf8_unchecked_mut(bytes) }
495    }
496}
497
498impl<A: Array<Item = u8>> AsRef<str> for SmallString<A> {
499    #[inline]
500    fn as_ref(&self) -> &str {
501        self
502    }
503}
504
505impl<A: Array<Item = u8>> AsMut<str> for SmallString<A> {
506    #[inline]
507    fn as_mut(&mut self) -> &mut str {
508        self
509    }
510}
511
512impl<A: Array<Item = u8>> Borrow<str> for SmallString<A> {
513    #[inline]
514    fn borrow(&self) -> &str {
515        self
516    }
517}
518
519impl<A: Array<Item = u8>> BorrowMut<str> for SmallString<A> {
520    #[inline]
521    fn borrow_mut(&mut self) -> &mut str {
522        self
523    }
524}
525
526impl<A: Array<Item = u8>> AsRef<[u8]> for SmallString<A> {
527    #[inline]
528    fn as_ref(&self) -> &[u8] {
529        self.data.as_ref()
530    }
531}
532
533impl<A: Array<Item = u8>> fmt::Write for SmallString<A> {
534    #[inline]
535    fn write_str(&mut self, s: &str) -> fmt::Result {
536        self.push_str(s);
537        Ok(())
538    }
539
540    #[inline]
541    fn write_char(&mut self, ch: char) -> fmt::Result {
542        self.push(ch);
543        Ok(())
544    }
545}
546
547impl<A: Array<Item = u8>> FromStr for SmallString<A> {
548    type Err = Infallible;
549
550    fn from_str(s: &str) -> Result<Self, Self::Err> {
551        Ok(SmallString::from(s))
552    }
553}
554
555#[cfg(feature = "serde")]
556impl<A: Array<Item = u8>> Serialize for SmallString<A> {
557    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
558        serializer.serialize_str(self)
559    }
560}
561
562#[cfg(feature = "serde")]
563impl<'de, A: Array<Item = u8>> Deserialize<'de> for SmallString<A> {
564    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
565        deserializer.deserialize_str(SmallStringVisitor {
566            phantom: PhantomData,
567        })
568    }
569}
570
571#[cfg(feature = "serde")]
572struct SmallStringVisitor<A> {
573    phantom: PhantomData<A>,
574}
575
576#[cfg(feature = "serde")]
577impl<'de, A: Array<Item = u8>> Visitor<'de> for SmallStringVisitor<A> {
578    type Value = SmallString<A>;
579
580    fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
581        f.write_str("a string")
582    }
583
584    fn visit_str<E: Error>(self, v: &str) -> Result<Self::Value, E> {
585        Ok(v.into())
586    }
587
588    fn visit_string<E: Error>(self, v: String) -> Result<Self::Value, E> {
589        Ok(v.into())
590    }
591}
592
593impl<A: Array<Item = u8>> From<char> for SmallString<A> {
594    #[inline]
595    fn from(ch: char) -> SmallString<A> {
596        SmallString::from_str(ch.encode_utf8(&mut [0; 4]))
597    }
598}
599
600impl<A: Array<Item = u8>> From<&'_ str> for SmallString<A> {
601    #[inline]
602    fn from(s: &str) -> SmallString<A> {
603        SmallString::from_str(s)
604    }
605}
606
607impl<A: Array<Item = u8>> From<Box<str>> for SmallString<A> {
608    #[inline]
609    fn from(s: Box<str>) -> SmallString<A> {
610        SmallString::from_string(s.into())
611    }
612}
613
614impl<A: Array<Item = u8>> From<String> for SmallString<A> {
615    #[inline]
616    fn from(s: String) -> SmallString<A> {
617        SmallString::from_string(s)
618    }
619}
620
621impl<'a, A: Array<Item = u8>> From<Cow<'a, str>> for SmallString<A> {
622    fn from(value: Cow<'a, str>) -> Self {
623        match value {
624            Cow::Borrowed(s) => Self::from_str(s),
625            Cow::Owned(s) => Self::from_string(s),
626        }
627    }
628}
629
630macro_rules! impl_index_str {
631    ($index_type: ty) => {
632        impl<A: Array<Item = u8>> ops::Index<$index_type> for SmallString<A> {
633            type Output = str;
634
635            #[inline]
636            fn index(&self, index: $index_type) -> &str {
637                &self.as_str()[index]
638            }
639        }
640
641        impl<A: Array<Item = u8>> ops::IndexMut<$index_type> for SmallString<A> {
642            #[inline]
643            fn index_mut(&mut self, index: $index_type) -> &mut str {
644                &mut self.as_mut_str()[index]
645            }
646        }
647    };
648}
649
650impl_index_str!(ops::Range<usize>);
651impl_index_str!(ops::RangeFrom<usize>);
652impl_index_str!(ops::RangeTo<usize>);
653impl_index_str!(ops::RangeFull);
654
655impl<A: Array<Item = u8>> FromIterator<char> for SmallString<A> {
656    fn from_iter<I: IntoIterator<Item = char>>(iter: I) -> SmallString<A> {
657        let mut s = SmallString::new();
658        s.extend(iter);
659        s
660    }
661}
662
663impl<'a, A: Array<Item = u8>> FromIterator<&'a char> for SmallString<A> {
664    fn from_iter<I: IntoIterator<Item = &'a char>>(iter: I) -> SmallString<A> {
665        let mut s = SmallString::new();
666        s.extend(iter.into_iter().cloned());
667        s
668    }
669}
670
671impl<'a, A: Array<Item = u8>> FromIterator<Cow<'a, str>> for SmallString<A> {
672    fn from_iter<I: IntoIterator<Item = Cow<'a, str>>>(iter: I) -> SmallString<A> {
673        let mut s = SmallString::new();
674        s.extend(iter);
675        s
676    }
677}
678
679impl<'a, A: Array<Item = u8>> FromIterator<&'a str> for SmallString<A> {
680    fn from_iter<I: IntoIterator<Item = &'a str>>(iter: I) -> SmallString<A> {
681        let mut s = SmallString::new();
682        s.extend(iter);
683        s
684    }
685}
686
687impl<A: Array<Item = u8>> FromIterator<String> for SmallString<A> {
688    fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> SmallString<A> {
689        let mut s = SmallString::new();
690        s.extend(iter);
691        s
692    }
693}
694
695impl<A: Array<Item = u8>> Extend<char> for SmallString<A> {
696    fn extend<I: IntoIterator<Item = char>>(&mut self, iter: I) {
697        let iter = iter.into_iter();
698        let (lo, _) = iter.size_hint();
699
700        self.reserve(lo);
701
702        for ch in iter {
703            self.push(ch);
704        }
705    }
706}
707
708impl<'a, A: Array<Item = u8>> Extend<&'a char> for SmallString<A> {
709    fn extend<I: IntoIterator<Item = &'a char>>(&mut self, iter: I) {
710        self.extend(iter.into_iter().cloned());
711    }
712}
713
714impl<'a, A: Array<Item = u8>> Extend<Cow<'a, str>> for SmallString<A> {
715    fn extend<I: IntoIterator<Item = Cow<'a, str>>>(&mut self, iter: I) {
716        for s in iter {
717            self.push_str(&s);
718        }
719    }
720}
721
722impl<'a, A: Array<Item = u8>> Extend<&'a str> for SmallString<A> {
723    fn extend<I: IntoIterator<Item = &'a str>>(&mut self, iter: I) {
724        for s in iter {
725            self.push_str(s);
726        }
727    }
728}
729
730impl<A: Array<Item = u8>> Extend<String> for SmallString<A> {
731    fn extend<I: IntoIterator<Item = String>>(&mut self, iter: I) {
732        for s in iter {
733            self.push_str(&s);
734        }
735    }
736}
737
738impl<A: Array<Item = u8>> fmt::Debug for SmallString<A> {
739    #[inline]
740    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
741        fmt::Debug::fmt(&**self, f)
742    }
743}
744
745impl<A: Array<Item = u8>> fmt::Display for SmallString<A> {
746    #[inline]
747    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
748        fmt::Display::fmt(&**self, f)
749    }
750}
751
752macro_rules! eq_str {
753    ( $rhs:ty ) => {
754        impl<'a, A: Array<Item = u8>> PartialEq<$rhs> for SmallString<A> {
755            #[inline]
756            fn eq(&self, rhs: &$rhs) -> bool {
757                self[..] == rhs[..]
758            }
759        }
760    };
761}
762
763eq_str!(str);
764eq_str!(&'a str);
765eq_str!(String);
766eq_str!(Cow<'a, str>);
767
768#[cfg(feature = "ffi")]
769impl<A: Array<Item = u8>> PartialEq<OsStr> for SmallString<A> {
770    #[inline]
771    fn eq(&self, rhs: &OsStr) -> bool {
772        &self[..] == rhs
773    }
774}
775
776#[cfg(feature = "ffi")]
777impl<'a, A: Array<Item = u8>> PartialEq<&'a OsStr> for SmallString<A> {
778    #[inline]
779    fn eq(&self, rhs: &&OsStr) -> bool {
780        &self[..] == *rhs
781    }
782}
783
784#[cfg(feature = "ffi")]
785impl<A: Array<Item = u8>> PartialEq<OsString> for SmallString<A> {
786    #[inline]
787    fn eq(&self, rhs: &OsString) -> bool {
788        &self[..] == rhs
789    }
790}
791
792#[cfg(feature = "ffi")]
793impl<'a, A: Array<Item = u8>> PartialEq<Cow<'a, OsStr>> for SmallString<A> {
794    #[inline]
795    fn eq(&self, rhs: &Cow<OsStr>) -> bool {
796        self[..] == **rhs
797    }
798}
799
800impl<A, B> PartialEq<SmallString<B>> for SmallString<A>
801where
802    A: Array<Item = u8>,
803    B: Array<Item = u8>,
804{
805    #[inline]
806    fn eq(&self, rhs: &SmallString<B>) -> bool {
807        self[..] == rhs[..]
808    }
809}
810
811impl<A: Array<Item = u8>> Eq for SmallString<A> {}
812
813impl<A: Array<Item = u8>> PartialOrd for SmallString<A> {
814    #[inline]
815    fn partial_cmp(&self, rhs: &SmallString<A>) -> Option<Ordering> {
816        Some(self.cmp(rhs))
817    }
818}
819
820impl<A: Array<Item = u8>> Ord for SmallString<A> {
821    #[inline]
822    fn cmp(&self, rhs: &SmallString<A>) -> Ordering {
823        self[..].cmp(&rhs[..])
824    }
825}
826
827impl<A: Array<Item = u8>> Hash for SmallString<A> {
828    #[inline]
829    fn hash<H: Hasher>(&self, state: &mut H) {
830        self[..].hash(state)
831    }
832}
833
834/// A draining iterator for `SmallString`.
835///
836/// This struct is created by the [`drain`] method on [`SmallString`].
837///
838/// [`drain`]: struct.SmallString.html#method.drain
839/// [`SmallString`]: struct.SmallString.html
840pub struct Drain<'a> {
841    iter: Chars<'a>,
842}
843
844impl<'a> Iterator for Drain<'a> {
845    type Item = char;
846
847    #[inline]
848    fn next(&mut self) -> Option<char> {
849        self.iter.next()
850    }
851
852    #[inline]
853    fn size_hint(&self) -> (usize, Option<usize>) {
854        self.iter.size_hint()
855    }
856}
857
858impl<'a> DoubleEndedIterator for Drain<'a> {
859    #[inline]
860    fn next_back(&mut self) -> Option<char> {
861        self.iter.next_back()
862    }
863}
864
865/// A range draining iterator for `SmallString`.
866///
867/// This struct is created by the [`drain_range`] method on [`SmallString`].
868///
869/// [`drain_range`]: struct.SmallString.html#method.drain_range
870/// [`SmallString`]: struct.SmallString.html
871pub struct DrainRange<'a, A: Array<Item = u8>> {
872    drain: smallvec::Drain<'a, A>,
873}
874
875impl<A: Array<Item = u8>> fmt::Debug for DrainRange<'_, A> {
876    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
877        self.drain.fmt(f)
878    }
879}
880
881impl<A: Array<Item = u8>> Iterator for DrainRange<'_, A> {
882    type Item = char;
883
884    fn next(&mut self) -> Option<Self::Item> {
885        let mut buf = [0; 4];
886
887        buf[0] = self.drain.next()?;
888        let utf8_len = 1.max(buf[0].leading_ones() as usize);
889
890        for b in &mut buf[1..utf8_len] {
891            *b = self.drain.next().unwrap();
892        }
893
894        unsafe { str::from_utf8_unchecked(&buf[..utf8_len]) }
895            .chars()
896            .next()
897    }
898
899    fn size_hint(&self) -> (usize, Option<usize>) {
900        let len = self.drain.len();
901        (len.div_ceil(4), Some(len))
902    }
903}
904
905impl<A: Array<Item = u8>> DoubleEndedIterator for DrainRange<'_, A> {
906    fn next_back(&mut self) -> Option<Self::Item> {
907        let mut buf = [0; 4];
908        let mut i = 3;
909
910        buf[i] = self.drain.next_back()?;
911
912        while buf[i].leading_ones() == 1 {
913            i -= 1;
914            buf[i] = self.drain.next_back().unwrap();
915        }
916
917        unsafe { str::from_utf8_unchecked(&buf[i..]) }
918            .chars()
919            .next()
920    }
921}
922impl<A: Array<Item = u8>> FusedIterator for DrainRange<'_, A> {}
923
924/// A possible error value when creating a `SmallString` from a byte array.
925///
926/// This type is the error type for the [`from_buf`] method on [`SmallString`].
927///
928/// [`from_buf`]: struct.SmallString.html#method.from_buf
929/// [`SmallString`]: struct.SmallString.html
930#[derive(Debug)]
931pub struct FromUtf8Error<A: Array<Item = u8>> {
932    buf: A,
933    error: Utf8Error,
934}
935
936impl<A: Array<Item = u8>> FromUtf8Error<A> {
937    /// Returns the slice of `[u8]` bytes that were attempted to convert to a `SmallString`.
938    #[inline]
939    pub fn as_bytes(&self) -> &[u8] {
940        let ptr = &self.buf as *const _ as *const u8;
941        unsafe { slice::from_raw_parts(ptr, A::size()) }
942    }
943
944    /// Returns the byte array that was attempted to convert into a `SmallString`.
945    #[inline]
946    pub fn into_buf(self) -> A {
947        self.buf
948    }
949
950    /// Returns the `Utf8Error` to get more details about the conversion failure.
951    #[inline]
952    pub fn utf8_error(&self) -> Utf8Error {
953        self.error
954    }
955}
956
957impl<A: Array<Item = u8>> fmt::Display for FromUtf8Error<A> {
958    #[inline]
959    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
960        fmt::Display::fmt(&self.error, f)
961    }
962}
963
964#[cfg(test)]
965mod test {
966    use alloc::{
967        borrow::{Cow, ToOwned},
968        str::FromStr,
969        string::{String, ToString},
970    };
971
972    use super::SmallString;
973
974    #[test]
975    fn test_drain() {
976        let mut s: SmallString<[u8; 2]> = SmallString::new();
977
978        s.push('a');
979        assert_eq!(s.drain().collect::<String>(), "a");
980        assert!(s.is_empty());
981
982        // spilling the vec
983        s.push('x');
984        s.push('y');
985        s.push('z');
986
987        assert_eq!(s.drain().collect::<String>(), "xyz");
988        assert!(s.is_empty());
989    }
990
991    #[test]
992    fn test_drain_range() {
993        let mut s: SmallString<[u8; 2]> = SmallString::new();
994
995        s.push('a');
996        assert_eq!(s.drain_range(..).collect::<String>(), "a");
997        assert!(s.is_empty());
998
999        s.push_str("xyz");
1000
1001        assert_eq!(s.drain_range(1..).collect::<String>(), "yz");
1002        assert_eq!(s, "x");
1003
1004        s.push_str("yz");
1005
1006        assert_eq!(s.drain_range(..2).collect::<String>(), "xy");
1007        assert_eq!(s, "z");
1008
1009        s.clear();
1010        s.push_str("测试文本");
1011
1012        assert_eq!(s.drain_range(3..9).collect::<String>(), "试文");
1013        assert_eq!(s, "测本");
1014    }
1015
1016    #[test]
1017    fn test_drain_rev() {
1018        let mut s: SmallString<[u8; 2]> = SmallString::new();
1019
1020        s.push('a');
1021        assert_eq!(s.drain().rev().collect::<String>(), "a");
1022        assert!(s.is_empty());
1023
1024        // spilling the vec
1025        s.push('x');
1026        s.push('y');
1027        s.push('z');
1028
1029        assert_eq!(s.drain().rev().collect::<String>(), "zyx");
1030        assert!(s.is_empty());
1031    }
1032
1033    #[test]
1034    fn test_drain_range_rev() {
1035        let mut s: SmallString<[u8; 2]> = SmallString::new();
1036
1037        s.push('a');
1038        assert_eq!(s.drain_range(..).rev().collect::<String>(), "a");
1039        assert!(s.is_empty());
1040
1041        // spilling the vec
1042        s.push_str("xyz");
1043
1044        assert_eq!(s.drain_range(..).rev().collect::<String>(), "zyx");
1045        assert!(s.is_empty());
1046
1047        s.push_str("xyz");
1048
1049        assert_eq!(s.drain_range(1..).rev().collect::<String>(), "zy");
1050        assert_eq!(s, "x");
1051
1052        s.push_str("yz");
1053
1054        assert_eq!(s.drain_range(..2).rev().collect::<String>(), "yx");
1055        assert_eq!(s, "z");
1056
1057        s.clear();
1058        s.push_str("测试文本");
1059
1060        assert_eq!(s.drain_range(3..9).rev().collect::<String>(), "文试");
1061        assert_eq!(s, "测本");
1062    }
1063
1064    #[test]
1065    fn test_eq() {
1066        let s: SmallString<[u8; 4]> = SmallString::from("foo");
1067
1068        assert_eq!(s, *"foo");
1069        assert_eq!(s, "foo");
1070        assert_eq!(s, "foo".to_owned());
1071        assert_eq!(s, Cow::Borrowed("foo"));
1072    }
1073
1074    #[cfg(feature = "ffi")]
1075    #[test]
1076    fn test_eq_os_str() {
1077        use std::ffi::OsStr;
1078
1079        let s: SmallString<[u8; 4]> = SmallString::from("foo");
1080        let os_s: &OsStr = "foo".as_ref();
1081
1082        assert_eq!(s, os_s);
1083        assert_eq!(s, *os_s);
1084        assert_eq!(s, os_s.to_owned());
1085        assert_eq!(s, Cow::Borrowed(os_s));
1086    }
1087
1088    #[test]
1089    fn test_from_buf() {
1090        let s: SmallString<[u8; 2]> = SmallString::from_buf([206, 177]).unwrap();
1091        assert_eq!(s, "α");
1092
1093        assert!(SmallString::<[u8; 2]>::from_buf([206, 0]).is_err());
1094    }
1095
1096    #[test]
1097    fn test_insert() {
1098        let mut s: SmallString<[u8; 8]> = SmallString::from("abc");
1099
1100        s.insert(1, 'x');
1101        assert_eq!(s, "axbc");
1102
1103        s.insert(3, 'α');
1104        assert_eq!(s, "axbαc");
1105
1106        s.insert_str(0, "foo");
1107        assert_eq!(s, "fooaxbαc");
1108    }
1109
1110    #[test]
1111    #[should_panic]
1112    fn test_insert_panic() {
1113        let mut s: SmallString<[u8; 8]> = SmallString::from("αβγ");
1114
1115        s.insert(1, 'x');
1116    }
1117
1118    #[test]
1119    fn test_into_string() {
1120        let s: SmallString<[u8; 2]> = SmallString::from("foo");
1121        assert_eq!(s.into_string(), "foo");
1122
1123        let s: SmallString<[u8; 8]> = SmallString::from("foo");
1124        assert_eq!(s.into_string(), "foo");
1125    }
1126
1127    #[test]
1128    fn test_to_string() {
1129        let s: SmallString<[u8; 2]> = SmallString::from("foo");
1130        assert_eq!(s.to_string(), "foo");
1131
1132        let s: SmallString<[u8; 8]> = SmallString::from("foo");
1133        assert_eq!(s.to_string(), "foo");
1134    }
1135
1136    #[test]
1137    fn test_pop() {
1138        let mut s: SmallString<[u8; 8]> = SmallString::from("αβγ");
1139
1140        assert_eq!(s.pop(), Some('γ'));
1141        assert_eq!(s.pop(), Some('β'));
1142        assert_eq!(s.pop(), Some('α'));
1143        assert_eq!(s.pop(), None);
1144    }
1145
1146    #[test]
1147    fn test_remove() {
1148        let mut s: SmallString<[u8; 8]> = SmallString::from("αβγ");
1149
1150        assert_eq!(s.remove(2), 'β');
1151        assert_eq!(s, "αγ");
1152
1153        assert_eq!(s.remove(0), 'α');
1154        assert_eq!(s, "γ");
1155
1156        assert_eq!(s.remove(0), 'γ');
1157        assert_eq!(s, "");
1158    }
1159
1160    #[test]
1161    #[should_panic]
1162    fn test_remove_panic_0() {
1163        let mut s: SmallString<[u8; 8]> = SmallString::from("foo");
1164
1165        // Attempt to remove at the end
1166        s.remove(3);
1167    }
1168
1169    #[test]
1170    #[should_panic]
1171    fn test_remove_panic_1() {
1172        let mut s: SmallString<[u8; 8]> = SmallString::from("αβγ");
1173
1174        // Attempt to remove mid-character
1175        s.remove(1);
1176    }
1177
1178    #[test]
1179    fn test_retain() {
1180        let mut s: SmallString<[u8; 8]> = SmallString::from("α_β_γ");
1181
1182        s.retain(|_| true);
1183        assert_eq!(s, "α_β_γ");
1184
1185        s.retain(|c| c != '_');
1186        assert_eq!(s, "αβγ");
1187
1188        s.retain(|c| c != 'β');
1189        assert_eq!(s, "αγ");
1190
1191        s.retain(|c| c == 'α');
1192        assert_eq!(s, "α");
1193
1194        s.retain(|_| false);
1195        assert_eq!(s, "");
1196    }
1197
1198    #[test]
1199    fn test_truncate() {
1200        let mut s: SmallString<[u8; 2]> = SmallString::from("foobar");
1201
1202        s.truncate(6);
1203        assert_eq!(s, "foobar");
1204
1205        s.truncate(3);
1206        assert_eq!(s, "foo");
1207    }
1208
1209    #[test]
1210    #[should_panic]
1211    fn test_truncate_panic() {
1212        let mut s: SmallString<[u8; 2]> = SmallString::from("α");
1213
1214        s.truncate(1);
1215    }
1216
1217    #[test]
1218    fn test_write() {
1219        use core::fmt::Write;
1220
1221        let mut s: SmallString<[u8; 8]> = SmallString::from("foo");
1222
1223        write!(s, "bar").unwrap();
1224
1225        assert_eq!(s, "foobar");
1226    }
1227
1228    #[test]
1229    fn test_from_str() {
1230        let s: SmallString<[u8; 8]> = FromStr::from_str("foo").unwrap();
1231
1232        assert_eq!(s, "foo");
1233    }
1234
1235    #[cfg(feature = "serde")]
1236    #[test]
1237    fn test_serde() {
1238        use bincode::{deserialize, serialize};
1239
1240        let mut small_str: SmallString<[u8; 4]> = SmallString::from("foo");
1241
1242        let encoded = serialize(&small_str).unwrap();
1243        let decoded: SmallString<[u8; 4]> = deserialize(&encoded).unwrap();
1244
1245        assert_eq!(small_str, decoded);
1246
1247        // Spill the vec
1248        small_str.push_str("bar");
1249
1250        // Check again after spilling.
1251        let encoded = serialize(&small_str).unwrap();
1252        let decoded: SmallString<[u8; 4]> = deserialize(&encoded).unwrap();
1253
1254        assert_eq!(small_str, decoded);
1255    }
1256}