inlinable_string/
string_ext.rs

1// Copyright 2015, The inlinable_string crate Developers. See the COPYRIGHT file
2// at the top-level directory of this distribution.
3//
4// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT
6// or http://opensource.org/licenses/MIT>, at your option. This file may not be
7// copied, modified, or distributed except according to those terms.
8
9//! A trait that exists to abstract string operations over any number of
10//! concrete string type implementations.
11//!
12//! See the [crate level documentation](./../index.html) for more.
13
14use alloc::borrow::{Borrow, Cow};
15use alloc::vec::Vec;
16use alloc::string::{String, FromUtf16Error, FromUtf8Error};
17use core::cmp::PartialEq;
18use core::fmt::Display;
19
20/// A trait that exists to abstract string operations over any number of
21/// concrete string type implementations.
22///
23/// See the [crate level documentation](./../index.html) for more.
24pub trait StringExt<'a>:
25    Borrow<str>
26    + Display
27    + PartialEq<str>
28    + PartialEq<&'a str>
29    + PartialEq<String>
30    + PartialEq<Cow<'a, str>>
31{
32    /// Creates a new string buffer initialized with the empty string.
33    ///
34    /// # Examples
35    ///
36    /// ```
37    /// use inlinable_string::{InlinableString, StringExt};
38    ///
39    /// let s = InlinableString::new();
40    /// ```
41    fn new() -> Self
42    where
43        Self: Sized;
44
45    /// Creates a new string buffer with the given capacity. The string will be
46    /// able to hold at least `capacity` bytes without reallocating. If
47    /// `capacity` is less than or equal to `INLINE_STRING_CAPACITY`, the string
48    /// will not heap allocate.
49    ///
50    /// # Examples
51    ///
52    /// ```
53    /// use inlinable_string::{InlinableString, StringExt};
54    ///
55    /// let s = InlinableString::with_capacity(10);
56    /// ```
57    fn with_capacity(capacity: usize) -> Self
58    where
59        Self: Sized;
60
61    /// Returns the vector as a string buffer, if possible, taking care not to
62    /// copy it.
63    ///
64    /// # Failure
65    ///
66    /// If the given vector is not valid UTF-8, then the original vector and the
67    /// corresponding error is returned.
68    ///
69    /// # Examples
70    ///
71    /// ```
72    /// use inlinable_string::{InlinableString, StringExt};
73    ///
74    /// let hello_vec = vec![104, 101, 108, 108, 111];
75    /// let s = InlinableString::from_utf8(hello_vec).unwrap();
76    /// assert_eq!(s, "hello");
77    ///
78    /// let invalid_vec = vec![240, 144, 128];
79    /// let s = InlinableString::from_utf8(invalid_vec).err().unwrap();
80    /// let err = s.utf8_error();
81    /// assert_eq!(s.into_bytes(), [240, 144, 128]);
82    /// ```
83    fn from_utf8(vec: Vec<u8>) -> Result<Self, FromUtf8Error>
84    where
85        Self: Sized;
86
87    /// Converts a vector of bytes to a new UTF-8 string.
88    /// Any invalid UTF-8 sequences are replaced with U+FFFD REPLACEMENT CHARACTER.
89    ///
90    /// # Examples
91    ///
92    /// ```
93    /// use inlinable_string::{InlinableString, StringExt};
94    ///
95    /// let input = b"Hello \xF0\x90\x80World";
96    /// let output = InlinableString::from_utf8_lossy(input);
97    /// assert_eq!(output, "Hello \u{FFFD}World");
98    /// ```
99    fn from_utf8_lossy(v: &'a [u8]) -> Cow<'a, str>
100    where
101        Self: Sized,
102    {
103        String::from_utf8_lossy(v)
104    }
105
106    /// Decode a UTF-16 encoded vector `v` into a `InlinableString`, returning `None`
107    /// if `v` contains any invalid data.
108    ///
109    /// # Examples
110    ///
111    /// ```
112    /// use inlinable_string::{InlinableString, StringExt};
113    ///
114    /// // 𝄞music
115    /// let mut v = &mut [0xD834, 0xDD1E, 0x006d, 0x0075,
116    ///                   0x0073, 0x0069, 0x0063];
117    /// assert_eq!(InlinableString::from_utf16(v).unwrap(),
118    ///            InlinableString::from("𝄞music"));
119    ///
120    /// // 𝄞mu<invalid>ic
121    /// v[4] = 0xD800;
122    /// assert!(InlinableString::from_utf16(v).is_err());
123    /// ```
124    fn from_utf16(v: &[u16]) -> Result<Self, FromUtf16Error>
125    where
126        Self: Sized;
127
128    /// Decode a UTF-16 encoded vector `v` into a string, replacing
129    /// invalid data with the replacement character (U+FFFD).
130    ///
131    /// # Examples
132    ///
133    /// ```
134    /// use inlinable_string::{InlinableString, StringExt};
135    ///
136    /// // 𝄞mus<invalid>ic<invalid>
137    /// let v = &[0xD834, 0xDD1E, 0x006d, 0x0075,
138    ///           0x0073, 0xDD1E, 0x0069, 0x0063,
139    ///           0xD834];
140    ///
141    /// assert_eq!(InlinableString::from_utf16_lossy(v),
142    ///            InlinableString::from("𝄞mus\u{FFFD}ic\u{FFFD}"));
143    /// ```
144    fn from_utf16_lossy(v: &[u16]) -> Self
145    where
146        Self: Sized;
147
148    /// Creates a new `InlinableString` from a length, capacity, and pointer.
149    ///
150    /// # Safety
151    ///
152    /// This is _very_ unsafe because:
153    ///
154    /// * We call `String::from_raw_parts` to get a `Vec<u8>`. Therefore, this
155    ///   function inherits all of its unsafety, see [its
156    ///   documentation](https://doc.rust-lang.org/nightly/collections/vec/struct.Vec.html#method.from_raw_parts)
157    ///   for the invariants it expects, they also apply to this function.
158    ///
159    /// * We assume that the `Vec` contains valid UTF-8.
160    unsafe fn from_raw_parts(buf: *mut u8, length: usize, capacity: usize) -> Self
161    where
162        Self: Sized;
163
164    /// Converts a vector of bytes to a new `InlinableString` without checking
165    /// if it contains valid UTF-8.
166    ///
167    /// # Safety
168    ///
169    /// This is unsafe because it assumes that the UTF-8-ness of the vector has
170    /// already been validated.
171    unsafe fn from_utf8_unchecked(bytes: Vec<u8>) -> Self
172    where
173        Self: Sized;
174
175    /// Returns the underlying byte buffer, encoded as UTF-8.
176    ///
177    /// # Examples
178    ///
179    /// ```
180    /// use inlinable_string::{InlinableString, StringExt};
181    ///
182    /// let s = InlinableString::from("hello");
183    /// let bytes = s.into_bytes();
184    /// assert_eq!(bytes, [104, 101, 108, 108, 111]);
185    /// ```
186    fn into_bytes(self) -> Vec<u8>;
187
188    /// Pushes the given string onto this string buffer.
189    ///
190    /// # Examples
191    ///
192    /// ```
193    /// use inlinable_string::{InlinableString, StringExt};
194    ///
195    /// let mut s = InlinableString::from("foo");
196    /// s.push_str("bar");
197    /// assert_eq!(s, "foobar");
198    /// ```
199    fn push_str(&mut self, string: &str);
200
201    /// Returns the number of bytes that this string buffer can hold without
202    /// reallocating.
203    ///
204    /// # Examples
205    ///
206    /// ```
207    /// use inlinable_string::{InlinableString, StringExt};
208    ///
209    /// let s = InlinableString::with_capacity(10);
210    /// assert!(s.capacity() >= 10);
211    /// ```
212    fn capacity(&self) -> usize;
213
214    /// Reserves capacity for at least `additional` more bytes to be inserted
215    /// in the given `InlinableString`. The collection may reserve more space to avoid
216    /// frequent reallocations.
217    ///
218    /// # Panics
219    ///
220    /// Panics if the new capacity overflows `usize`.
221    ///
222    /// # Examples
223    ///
224    /// ```
225    /// use inlinable_string::{InlinableString, StringExt};
226    ///
227    /// let mut s = InlinableString::new();
228    /// s.reserve(10);
229    /// assert!(s.capacity() >= 10);
230    /// ```
231    fn reserve(&mut self, additional: usize);
232
233    /// Reserves the minimum capacity for exactly `additional` more bytes to be
234    /// inserted in the given `InlinableString`. Does nothing if the capacity is already
235    /// sufficient.
236    ///
237    /// Note that the allocator may give the collection more space than it
238    /// requests. Therefore capacity can not be relied upon to be precisely
239    /// minimal. Prefer `reserve` if future insertions are expected.
240    ///
241    /// # Panics
242    ///
243    /// Panics if the new capacity overflows `usize`.
244    ///
245    /// # Examples
246    ///
247    /// ```
248    /// use inlinable_string::{InlinableString, StringExt};
249    ///
250    /// let mut s = InlinableString::new();
251    /// s.reserve_exact(10);
252    /// assert!(s.capacity() >= 10);
253    /// ```
254    fn reserve_exact(&mut self, additional: usize);
255
256    /// Shrinks the capacity of this string buffer to match its length. If the
257    /// string's length is less than `INLINE_STRING_CAPACITY` and the string is
258    /// heap-allocated, then it is demoted to inline storage.
259    ///
260    /// # Examples
261    ///
262    /// ```
263    /// use inlinable_string::{InlinableString, StringExt};
264    ///
265    /// let mut s = InlinableString::from("foo");
266    /// s.reserve(100);
267    /// assert!(s.capacity() >= 100);
268    /// s.shrink_to_fit();
269    /// assert_eq!(s.capacity(), inlinable_string::INLINE_STRING_CAPACITY);
270    /// ```
271    fn shrink_to_fit(&mut self);
272
273    /// Adds the given character to the end of the string.
274    ///
275    /// # Examples
276    ///
277    /// ```
278    /// use inlinable_string::{InlinableString, StringExt};
279    ///
280    /// let mut s = InlinableString::from("abc");
281    /// s.push('1');
282    /// s.push('2');
283    /// s.push('3');
284    /// assert_eq!(s, "abc123");
285    /// ```
286    fn push(&mut self, ch: char);
287
288    /// Works with the underlying buffer as a byte slice.
289    ///
290    /// # Examples
291    ///
292    /// ```
293    /// use inlinable_string::{InlinableString, StringExt};
294    ///
295    /// let s = InlinableString::from("hello");
296    /// assert_eq!(s.as_bytes(), [104, 101, 108, 108, 111]);
297    /// ```
298    fn as_bytes(&self) -> &[u8];
299
300    /// Shortens a string to the specified length.
301    ///
302    /// # Panics
303    ///
304    /// Panics if `new_len` > current length, or if `new_len` is not a character
305    /// boundary.
306    ///
307    /// # Examples
308    ///
309    /// ```
310    /// use inlinable_string::{InlinableString, StringExt};
311    ///
312    /// let mut s = InlinableString::from("hello");
313    /// s.truncate(2);
314    /// assert_eq!(s, "he");
315    /// ```
316    fn truncate(&mut self, new_len: usize);
317
318    /// Removes the last character from the string buffer and returns it.
319    /// Returns `None` if this string buffer is empty.
320    ///
321    /// # Examples
322    ///
323    /// ```
324    /// use inlinable_string::{InlinableString, StringExt};
325    ///
326    /// let mut s = InlinableString::from("foo");
327    /// assert_eq!(s.pop(), Some('o'));
328    /// assert_eq!(s.pop(), Some('o'));
329    /// assert_eq!(s.pop(), Some('f'));
330    /// assert_eq!(s.pop(), None);
331    /// ```
332    fn pop(&mut self) -> Option<char>;
333
334    /// Removes the character from the string buffer at byte position `idx` and
335    /// returns it.
336    ///
337    /// # Warning
338    ///
339    /// This is an O(n) operation as it requires copying every element in the
340    /// buffer.
341    ///
342    /// # Panics
343    ///
344    /// If `idx` does not lie on a character boundary, or if it is out of
345    /// bounds, then this function will panic.
346    ///
347    /// # Examples
348    ///
349    /// ```
350    /// use inlinable_string::{InlinableString, StringExt};
351    ///
352    /// let mut s = InlinableString::from("foo");
353    /// assert_eq!(s.remove(0), 'f');
354    /// assert_eq!(s.remove(1), 'o');
355    /// assert_eq!(s.remove(0), 'o');
356    /// ```
357    fn remove(&mut self, idx: usize) -> char;
358
359    /// Inserts a character into the string buffer at byte position `idx`.
360    ///
361    /// # Warning
362    ///
363    /// This is an O(n) operation as it requires copying every element in the
364    /// buffer.
365    ///
366    /// # Examples
367    ///
368    /// ```
369    /// use inlinable_string::{InlinableString, StringExt};
370    ///
371    /// let mut s = InlinableString::from("foo");
372    /// s.insert(2, 'f');
373    /// assert!(s == "fofo");
374    /// ```
375    ///
376    /// # Panics
377    ///
378    /// If `idx` does not lie on a character boundary or is out of bounds, then
379    /// this function will panic.
380    fn insert(&mut self, idx: usize, ch: char);
381
382    /// Inserts a string into the string buffer at byte position `idx`.
383    ///
384    /// # Warning
385    ///
386    /// This is an O(n) operation as it requires copying every element in the
387    /// buffer.
388    ///
389    /// # Examples
390    ///
391    /// ```
392    /// use inlinable_string::{InlinableString, StringExt};
393    ///
394    /// let mut s = InlinableString::from("foo");
395    /// s.insert_str(2, "bar");
396    /// assert!(s == "fobaro");
397    /// ```
398    ///
399    /// # Panics
400    ///
401    /// If `idx` does not lie on a character boundary or is out of bounds, then
402    /// this function will panic.
403    fn insert_str(&mut self, idx: usize, string: &str);
404
405    /// Views the string buffer as a mutable sequence of bytes.
406    ///
407    /// # Safety
408    ///
409    /// This is unsafe because it does not check to ensure that the resulting
410    /// string will be valid UTF-8.
411    ///
412    /// # Examples
413    ///
414    /// ```
415    /// use inlinable_string::{InlinableString, StringExt};
416    ///
417    /// let mut s = InlinableString::from("hello");
418    /// unsafe {
419    ///     let slice = s.as_mut_slice();
420    ///     assert!(slice == &[104, 101, 108, 108, 111]);
421    ///     slice.reverse();
422    /// }
423    /// assert_eq!(s, "olleh");
424    /// ```
425    unsafe fn as_mut_slice(&mut self) -> &mut [u8];
426
427    /// Returns the number of bytes in this string.
428    ///
429    /// # Examples
430    ///
431    /// ```
432    /// use inlinable_string::{InlinableString, StringExt};
433    ///
434    /// let a = InlinableString::from("foo");
435    /// assert_eq!(a.len(), 3);
436    /// ```
437    fn len(&self) -> usize;
438
439    /// Returns true if the string contains no bytes
440    ///
441    /// # Examples
442    ///
443    /// ```
444    /// use inlinable_string::{InlinableString, StringExt};
445    ///
446    /// let mut v = InlinableString::new();
447    /// assert!(v.is_empty());
448    /// v.push('a');
449    /// assert!(!v.is_empty());
450    /// ```
451    #[inline]
452    fn is_empty(&self) -> bool {
453        self.len() == 0
454    }
455
456    /// Truncates the string, returning it to 0 length.
457    ///
458    /// # Examples
459    ///
460    /// ```
461    /// use inlinable_string::{InlinableString, StringExt};
462    ///
463    /// let mut s = InlinableString::from("foo");
464    /// s.clear();
465    /// assert!(s.is_empty());
466    /// ```
467    #[inline]
468    fn clear(&mut self) {
469        self.truncate(0);
470    }
471}
472
473impl<'a> StringExt<'a> for String {
474    #[inline]
475    fn new() -> Self {
476        String::new()
477    }
478
479    #[inline]
480    fn with_capacity(capacity: usize) -> Self {
481        String::with_capacity(capacity)
482    }
483
484    #[inline]
485    fn from_utf8(vec: Vec<u8>) -> Result<Self, FromUtf8Error> {
486        String::from_utf8(vec)
487    }
488
489    #[inline]
490    fn from_utf16(v: &[u16]) -> Result<Self, FromUtf16Error> {
491        String::from_utf16(v)
492    }
493
494    #[inline]
495    fn from_utf16_lossy(v: &[u16]) -> Self {
496        String::from_utf16_lossy(v)
497    }
498
499    #[inline]
500    unsafe fn from_raw_parts(buf: *mut u8, length: usize, capacity: usize) -> Self {
501        String::from_raw_parts(buf, length, capacity)
502    }
503
504    #[inline]
505    unsafe fn from_utf8_unchecked(bytes: Vec<u8>) -> Self {
506        String::from_utf8_unchecked(bytes)
507    }
508
509    #[inline]
510    fn into_bytes(self) -> Vec<u8> {
511        String::into_bytes(self)
512    }
513
514    #[inline]
515    fn push_str(&mut self, string: &str) {
516        String::push_str(self, string)
517    }
518
519    #[inline]
520    fn capacity(&self) -> usize {
521        String::capacity(self)
522    }
523
524    #[inline]
525    fn reserve(&mut self, additional: usize) {
526        String::reserve(self, additional)
527    }
528
529    #[inline]
530    fn reserve_exact(&mut self, additional: usize) {
531        String::reserve_exact(self, additional)
532    }
533
534    #[inline]
535    fn shrink_to_fit(&mut self) {
536        String::shrink_to_fit(self)
537    }
538
539    #[inline]
540    fn push(&mut self, ch: char) {
541        String::push(self, ch)
542    }
543
544    #[inline]
545    fn as_bytes(&self) -> &[u8] {
546        String::as_bytes(self)
547    }
548
549    #[inline]
550    fn truncate(&mut self, new_len: usize) {
551        String::truncate(self, new_len)
552    }
553
554    #[inline]
555    fn pop(&mut self) -> Option<char> {
556        String::pop(self)
557    }
558
559    #[inline]
560    fn remove(&mut self, idx: usize) -> char {
561        String::remove(self, idx)
562    }
563
564    #[inline]
565    fn insert(&mut self, idx: usize, ch: char) {
566        String::insert(self, idx, ch)
567    }
568
569    #[inline]
570    fn insert_str(&mut self, idx: usize, string: &str) {
571        String::insert_str(self, idx, string)
572    }
573
574    #[inline]
575    unsafe fn as_mut_slice(&mut self) -> &mut [u8] {
576        &mut *(self.as_mut_str() as *mut str as *mut [u8])
577    }
578
579    #[inline]
580    fn len(&self) -> usize {
581        String::len(self)
582    }
583}
584
585#[cfg(test)]
586mod std_string_stringext_sanity_tests {
587    // Sanity tests for std::string::String's StringExt implementation.
588
589    use alloc::string::String;
590    use super::StringExt;
591
592    #[test]
593    fn test_new() {
594        let s = <String as StringExt>::new();
595        assert!(StringExt::is_empty(&s));
596    }
597
598    #[test]
599    fn test_with_capacity() {
600        let s = <String as StringExt>::with_capacity(10);
601        assert!(StringExt::capacity(&s) >= 10);
602    }
603
604    #[test]
605    fn test_from_utf8() {
606        let s = <String as StringExt>::from_utf8(vec![104, 101, 108, 108, 111]);
607        assert_eq!(s.unwrap(), "hello");
608    }
609
610    #[test]
611    fn test_from_utf16() {
612        let v = &mut [0xD834, 0xDD1E, 0x006d, 0x0075, 0x0073, 0x0069, 0x0063];
613        let s = <String as StringExt>::from_utf16(v);
614        assert_eq!(s.unwrap(), "𝄞music");
615    }
616
617    #[test]
618    fn test_from_utf16_lossy() {
619        let input = b"Hello \xF0\x90\x80World";
620        let output = <String as StringExt>::from_utf8_lossy(input);
621        assert_eq!(output, "Hello \u{FFFD}World");
622    }
623
624    #[test]
625    fn test_into_bytes() {
626        let s = String::from("hello");
627        let bytes = StringExt::into_bytes(s);
628        assert_eq!(bytes, [104, 101, 108, 108, 111]);
629    }
630
631    #[test]
632    fn test_push_str() {
633        let mut s = String::from("hello");
634        StringExt::push_str(&mut s, " world");
635        assert_eq!(s, "hello world");
636    }
637
638    #[test]
639    fn test_capacity() {
640        let s = <String as StringExt>::with_capacity(100);
641        assert!(String::capacity(&s) >= 100);
642    }
643
644    #[test]
645    fn test_reserve() {
646        let mut s = <String as StringExt>::new();
647        StringExt::reserve(&mut s, 100);
648        assert!(String::capacity(&s) >= 100);
649    }
650
651    #[test]
652    fn test_reserve_exact() {
653        let mut s = <String as StringExt>::new();
654        StringExt::reserve_exact(&mut s, 100);
655        assert!(String::capacity(&s) >= 100);
656    }
657
658    #[test]
659    fn test_shrink_to_fit() {
660        let mut s = <String as StringExt>::with_capacity(100);
661        StringExt::push_str(&mut s, "foo");
662        StringExt::shrink_to_fit(&mut s);
663        assert_eq!(String::capacity(&s), 3);
664    }
665
666    #[test]
667    fn test_push() {
668        let mut s = String::new();
669        StringExt::push(&mut s, 'a');
670        assert_eq!(s, "a");
671    }
672
673    #[test]
674    fn test_truncate() {
675        let mut s = String::from("foo");
676        StringExt::truncate(&mut s, 1);
677        assert_eq!(s, "f");
678    }
679
680    #[test]
681    fn test_pop() {
682        let mut s = String::from("foo");
683        assert_eq!(StringExt::pop(&mut s), Some('o'));
684        assert_eq!(StringExt::pop(&mut s), Some('o'));
685        assert_eq!(StringExt::pop(&mut s), Some('f'));
686        assert_eq!(StringExt::pop(&mut s), None);
687    }
688}