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}