1#![forbid(missing_docs)]
77#![cfg_attr(feature = "nightly", feature(plugin))]
78#![cfg_attr(all(test, feature = "nightly"), feature(test))]
79#![cfg_attr(feature = "no_std", no_std)]
80
81#[allow(unused_imports)]
82#[cfg_attr(feature = "no_std", macro_use)]
83extern crate alloc;
84
85#[cfg(test)]
86#[cfg(feature = "nightly")]
87extern crate test;
88
89#[cfg(feature = "serde")]
90mod serde_impl;
91
92pub mod inline_string;
93pub mod string_ext;
94
95pub use inline_string::{InlineString, INLINE_STRING_CAPACITY};
96pub use string_ext::StringExt;
97
98use alloc::borrow::{Borrow, Cow};
99use alloc::vec::Vec;
100use alloc::string::{FromUtf16Error, FromUtf8Error, String};
101use core::cmp::Ordering;
102use core::convert;
103use core::fmt;
104use core::hash;
105use core::iter;
106use core::mem;
107use core::ops;
108use core::str::FromStr;
109
110#[derive(Clone, Eq)]
115pub enum InlinableString {
116 Heap(String),
118 Inline(InlineString),
120}
121
122impl fmt::Debug for InlinableString {
123 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124 fmt::Debug::fmt(&self as &str, f)
125 }
126}
127
128impl iter::FromIterator<char> for InlinableString {
129 fn from_iter<I: IntoIterator<Item = char>>(iter: I) -> InlinableString {
130 let mut buf = InlinableString::new();
131 buf.extend(iter);
132 buf
133 }
134}
135
136impl<'a> iter::FromIterator<&'a str> for InlinableString {
137 fn from_iter<I: IntoIterator<Item = &'a str>>(iter: I) -> InlinableString {
138 let mut buf = InlinableString::new();
139 buf.extend(iter);
140 buf
141 }
142}
143
144impl Extend<char> for InlinableString {
145 fn extend<I: IntoIterator<Item = char>>(&mut self, iterable: I) {
146 let iterator = iterable.into_iter();
147 let (lower_bound, _) = iterator.size_hint();
148 self.reserve(lower_bound);
149 for ch in iterator {
150 self.push(ch);
151 }
152 }
153}
154
155impl<'a> Extend<&'a char> for InlinableString {
156 fn extend<I: IntoIterator<Item = &'a char>>(&mut self, iter: I) {
157 self.extend(iter.into_iter().cloned());
158 }
159}
160
161impl<'a> Extend<&'a str> for InlinableString {
162 fn extend<I: IntoIterator<Item = &'a str>>(&mut self, iterable: I) {
163 let iterator = iterable.into_iter();
164 let (lower_bound, _) = iterator.size_hint();
165 self.reserve(lower_bound);
166 for s in iterator {
167 self.push_str(s);
168 }
169 }
170}
171
172impl<'a> ops::Add<&'a str> for InlinableString {
173 type Output = InlinableString;
174
175 #[inline]
176 fn add(mut self, other: &str) -> InlinableString {
177 self.push_str(other);
178 self
179 }
180}
181
182impl PartialOrd<InlinableString> for InlinableString {
183 fn partial_cmp(&self, rhs: &InlinableString) -> Option<Ordering> {
184 Some(Ord::cmp(&self[..], &rhs[..]))
185 }
186}
187
188impl Ord for InlinableString {
189 #[inline]
190 fn cmp(&self, rhs: &InlinableString) -> Ordering {
191 Ord::cmp(&self[..], &rhs[..])
192 }
193}
194
195impl hash::Hash for InlinableString {
196 #[inline]
197 fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
198 (**self).hash(hasher)
199 }
200}
201
202impl Borrow<str> for InlinableString {
203 fn borrow(&self) -> &str {
204 &*self
205 }
206}
207
208impl AsRef<str> for InlinableString {
209 fn as_ref(&self) -> &str {
210 match *self {
211 InlinableString::Heap(ref s) => &*s,
212 InlinableString::Inline(ref s) => &*s,
213 }
214 }
215}
216
217impl AsMut<str> for InlinableString {
218 fn as_mut(&mut self) -> &mut str {
219 match *self {
220 InlinableString::Heap(ref mut s) => s.as_mut_str(),
221 InlinableString::Inline(ref mut s) => &mut s[..],
222 }
223 }
224}
225
226impl<'a> From<&'a str> for InlinableString {
227 #[inline]
228 fn from(string: &'a str) -> InlinableString {
229 if string.len() <= INLINE_STRING_CAPACITY {
230 InlinableString::Inline(string.into())
231 } else {
232 InlinableString::Heap(string.into())
233 }
234 }
235}
236
237impl From<String> for InlinableString {
238 #[inline]
239 fn from(string: String) -> InlinableString {
240 if string.len() <= INLINE_STRING_CAPACITY {
241 InlinableString::Inline(string.as_str().into())
242 } else {
243 InlinableString::Heap(string)
244 }
245 }
246}
247
248impl FromStr for InlinableString {
249 type Err = convert::Infallible;
250
251 #[inline]
252 fn from_str(s: &str) -> Result<InlinableString, convert::Infallible> {
253 Ok(InlinableString::from(s))
254 }
255}
256
257impl Default for InlinableString {
258 fn default() -> Self {
259 InlinableString::new()
260 }
261}
262
263impl fmt::Display for InlinableString {
264 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
265 match *self {
266 InlinableString::Heap(ref s) => s.fmt(f),
267 InlinableString::Inline(ref s) => s.fmt(f),
268 }
269 }
270}
271
272impl fmt::Write for InlinableString {
273 fn write_char(&mut self, ch: char) -> Result<(), fmt::Error> {
274 self.push(ch);
275 Ok(())
276 }
277 fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
278 self.push_str(s);
279 Ok(())
280 }
281}
282
283impl ops::Index<ops::Range<usize>> for InlinableString {
284 type Output = str;
285
286 #[inline]
287 fn index(&self, index: ops::Range<usize>) -> &str {
288 match *self {
289 InlinableString::Heap(ref s) => s.index(index),
290 InlinableString::Inline(ref s) => s.index(index),
291 }
292 }
293}
294
295impl ops::Index<ops::RangeTo<usize>> for InlinableString {
296 type Output = str;
297
298 #[inline]
299 fn index(&self, index: ops::RangeTo<usize>) -> &str {
300 match *self {
301 InlinableString::Heap(ref s) => s.index(index),
302 InlinableString::Inline(ref s) => s.index(index),
303 }
304 }
305}
306
307impl ops::Index<ops::RangeFrom<usize>> for InlinableString {
308 type Output = str;
309
310 #[inline]
311 fn index(&self, index: ops::RangeFrom<usize>) -> &str {
312 match *self {
313 InlinableString::Heap(ref s) => s.index(index),
314 InlinableString::Inline(ref s) => s.index(index),
315 }
316 }
317}
318
319impl ops::Index<ops::RangeFull> for InlinableString {
320 type Output = str;
321
322 #[inline]
323 fn index(&self, index: ops::RangeFull) -> &str {
324 match *self {
325 InlinableString::Heap(ref s) => s.index(index),
326 InlinableString::Inline(ref s) => s.index(index),
327 }
328 }
329}
330
331impl ops::IndexMut<ops::Range<usize>> for InlinableString {
332 #[inline]
333 fn index_mut(&mut self, index: ops::Range<usize>) -> &mut str {
334 match *self {
335 InlinableString::Heap(ref mut s) => s.index_mut(index),
336 InlinableString::Inline(ref mut s) => s.index_mut(index),
337 }
338 }
339}
340
341impl ops::IndexMut<ops::RangeTo<usize>> for InlinableString {
342 #[inline]
343 fn index_mut(&mut self, index: ops::RangeTo<usize>) -> &mut str {
344 match *self {
345 InlinableString::Heap(ref mut s) => s.index_mut(index),
346 InlinableString::Inline(ref mut s) => s.index_mut(index),
347 }
348 }
349}
350
351impl ops::IndexMut<ops::RangeFrom<usize>> for InlinableString {
352 #[inline]
353 fn index_mut(&mut self, index: ops::RangeFrom<usize>) -> &mut str {
354 match *self {
355 InlinableString::Heap(ref mut s) => s.index_mut(index),
356 InlinableString::Inline(ref mut s) => s.index_mut(index),
357 }
358 }
359}
360
361impl ops::IndexMut<ops::RangeFull> for InlinableString {
362 #[inline]
363 fn index_mut(&mut self, index: ops::RangeFull) -> &mut str {
364 match *self {
365 InlinableString::Heap(ref mut s) => s.index_mut(index),
366 InlinableString::Inline(ref mut s) => s.index_mut(index),
367 }
368 }
369}
370
371impl ops::Deref for InlinableString {
372 type Target = str;
373
374 #[inline]
375 fn deref(&self) -> &str {
376 match *self {
377 InlinableString::Heap(ref s) => s.deref(),
378 InlinableString::Inline(ref s) => s.deref(),
379 }
380 }
381}
382
383impl ops::DerefMut for InlinableString {
384 #[inline]
385 fn deref_mut(&mut self) -> &mut str {
386 match *self {
387 InlinableString::Heap(ref mut s) => s.deref_mut(),
388 InlinableString::Inline(ref mut s) => s.deref_mut(),
389 }
390 }
391}
392
393impl PartialEq<InlinableString> for InlinableString {
394 #[inline]
395 fn eq(&self, rhs: &InlinableString) -> bool {
396 PartialEq::eq(&self[..], &rhs[..])
397 }
398}
399
400macro_rules! impl_eq {
401 ($lhs:ty, $rhs: ty) => {
402 impl<'a> PartialEq<$rhs> for $lhs {
403 #[inline]
404 fn eq(&self, other: &$rhs) -> bool {
405 PartialEq::eq(&self[..], &other[..])
406 }
407 }
408
409 impl<'a> PartialEq<$lhs> for $rhs {
410 #[inline]
411 fn eq(&self, other: &$lhs) -> bool {
412 PartialEq::eq(&self[..], &other[..])
413 }
414 }
415 };
416}
417
418impl_eq! { InlinableString, str }
419impl_eq! { InlinableString, String }
420impl_eq! { InlinableString, &'a str }
421impl_eq! { InlinableString, InlineString }
422impl_eq! { Cow<'a, str>, InlinableString }
423
424impl<'a> StringExt<'a> for InlinableString {
425 #[inline]
426 fn new() -> Self {
427 InlinableString::Inline(InlineString::new())
428 }
429
430 #[inline]
431 fn with_capacity(capacity: usize) -> Self {
432 if capacity <= INLINE_STRING_CAPACITY {
433 InlinableString::Inline(InlineString::new())
434 } else {
435 InlinableString::Heap(String::with_capacity(capacity))
436 }
437 }
438
439 #[inline]
440 fn from_utf8(vec: Vec<u8>) -> Result<Self, FromUtf8Error> {
441 String::from_utf8(vec).map(InlinableString::Heap)
442 }
443
444 #[inline]
445 fn from_utf16(v: &[u16]) -> Result<Self, FromUtf16Error> {
446 String::from_utf16(v).map(InlinableString::Heap)
447 }
448
449 #[inline]
450 fn from_utf16_lossy(v: &[u16]) -> Self {
451 InlinableString::Heap(String::from_utf16_lossy(v))
452 }
453
454 #[inline]
455 unsafe fn from_raw_parts(buf: *mut u8, length: usize, capacity: usize) -> Self {
456 InlinableString::Heap(String::from_raw_parts(buf, length, capacity))
457 }
458
459 #[inline]
460 unsafe fn from_utf8_unchecked(bytes: Vec<u8>) -> Self {
461 InlinableString::Heap(String::from_utf8_unchecked(bytes))
462 }
463
464 #[inline]
465 fn into_bytes(self) -> Vec<u8> {
466 match self {
467 InlinableString::Heap(s) => s.into_bytes(),
468 InlinableString::Inline(s) => Vec::from(&s[..]),
469 }
470 }
471
472 #[inline]
473 fn push_str(&mut self, string: &str) {
474 let promoted = match *self {
475 InlinableString::Inline(ref mut s) => {
476 if s.push_str(string).is_ok() {
477 return;
478 }
479 let mut promoted = String::with_capacity(string.len() + s.len());
480 promoted.push_str(&*s);
481 promoted.push_str(string);
482 promoted
483 }
484 InlinableString::Heap(ref mut s) => {
485 s.push_str(string);
486 return;
487 }
488 };
489 mem::swap(self, &mut InlinableString::Heap(promoted));
490 }
491
492 #[inline]
493 fn capacity(&self) -> usize {
494 match *self {
495 InlinableString::Heap(ref s) => s.capacity(),
496 InlinableString::Inline(_) => INLINE_STRING_CAPACITY,
497 }
498 }
499
500 #[inline]
501 fn reserve(&mut self, additional: usize) {
502 let promoted = match *self {
503 InlinableString::Inline(ref s) => {
504 let new_capacity = s.len() + additional;
505 if new_capacity <= INLINE_STRING_CAPACITY {
506 return;
507 }
508 let mut promoted = String::with_capacity(new_capacity);
509 promoted.push_str(&s);
510 promoted
511 }
512 InlinableString::Heap(ref mut s) => {
513 s.reserve(additional);
514 return;
515 }
516 };
517 mem::swap(self, &mut InlinableString::Heap(promoted));
518 }
519
520 #[inline]
521 fn reserve_exact(&mut self, additional: usize) {
522 let promoted = match *self {
523 InlinableString::Inline(ref s) => {
524 let new_capacity = s.len() + additional;
525 if new_capacity <= INLINE_STRING_CAPACITY {
526 return;
527 }
528 let mut promoted = String::with_capacity(new_capacity);
529 promoted.push_str(&s);
530 promoted
531 }
532 InlinableString::Heap(ref mut s) => {
533 s.reserve_exact(additional);
534 return;
535 }
536 };
537 mem::swap(self, &mut InlinableString::Heap(promoted));
538 }
539
540 #[inline]
541 fn shrink_to_fit(&mut self) {
542 if self.len() <= INLINE_STRING_CAPACITY {
543 let demoted = if let InlinableString::Heap(ref s) = *self {
544 InlineString::from(&s[..])
545 } else {
546 return;
547 };
548 mem::swap(self, &mut InlinableString::Inline(demoted));
549 return;
550 }
551
552 match *self {
553 InlinableString::Heap(ref mut s) => s.shrink_to_fit(),
554 _ => panic!("inlinable_string: internal error: this branch should be unreachable"),
555 };
556 }
557
558 #[inline]
559 fn push(&mut self, ch: char) {
560 let promoted = match *self {
561 InlinableString::Inline(ref mut s) => {
562 if s.push(ch).is_ok() {
563 return;
564 }
565
566 let mut promoted = String::with_capacity(s.len() + 1);
567 promoted.push_str(&*s);
568 promoted.push(ch);
569 promoted
570 }
571 InlinableString::Heap(ref mut s) => {
572 s.push(ch);
573 return;
574 }
575 };
576
577 mem::swap(self, &mut InlinableString::Heap(promoted));
578 }
579
580 #[inline]
581 fn as_bytes(&self) -> &[u8] {
582 match *self {
583 InlinableString::Heap(ref s) => s.as_bytes(),
584 InlinableString::Inline(ref s) => s.as_bytes(),
585 }
586 }
587
588 #[inline]
589 fn truncate(&mut self, new_len: usize) {
590 match *self {
591 InlinableString::Heap(ref mut s) => s.truncate(new_len),
592 InlinableString::Inline(ref mut s) => s.truncate(new_len),
593 };
594 }
595
596 #[inline]
597 fn pop(&mut self) -> Option<char> {
598 match *self {
599 InlinableString::Heap(ref mut s) => s.pop(),
600 InlinableString::Inline(ref mut s) => s.pop(),
601 }
602 }
603
604 #[inline]
605 fn remove(&mut self, idx: usize) -> char {
606 match *self {
607 InlinableString::Heap(ref mut s) => s.remove(idx),
608 InlinableString::Inline(ref mut s) => s.remove(idx),
609 }
610 }
611
612 #[inline]
613 fn insert(&mut self, idx: usize, ch: char) {
614 let promoted = match *self {
615 InlinableString::Heap(ref mut s) => {
616 s.insert(idx, ch);
617 return;
618 }
619 InlinableString::Inline(ref mut s) => {
620 if s.insert(idx, ch).is_ok() {
621 return;
622 }
623
624 let mut promoted = String::with_capacity(s.len() + 1);
625 promoted.push_str(&s[..idx]);
626 promoted.push(ch);
627 promoted.push_str(&s[idx..]);
628 promoted
629 }
630 };
631
632 mem::swap(self, &mut InlinableString::Heap(promoted));
633 }
634
635 #[inline]
636 fn insert_str(&mut self, idx: usize, string: &str) {
637 let promoted = match *self {
638 InlinableString::Heap(ref mut s) => {
639 s.insert_str(idx, string);
640 return;
641 }
642 InlinableString::Inline(ref mut s) => {
643 if s.insert_str(idx, string).is_ok() {
644 return;
645 }
646
647 let mut promoted = String::with_capacity(s.len() + string.len());
648 promoted.push_str(&s[..idx]);
649 promoted.push_str(string);
650 promoted.push_str(&s[idx..]);
651 promoted
652 }
653 };
654
655 mem::swap(self, &mut InlinableString::Heap(promoted));
656 }
657
658 #[inline]
659 unsafe fn as_mut_slice(&mut self) -> &mut [u8] {
660 match *self {
661 InlinableString::Heap(ref mut s) => &mut s.as_mut_vec()[..],
662 InlinableString::Inline(ref mut s) => s.as_mut_slice(),
663 }
664 }
665
666 #[inline]
667 fn len(&self) -> usize {
668 match *self {
669 InlinableString::Heap(ref s) => s.len(),
670 InlinableString::Inline(ref s) => s.len(),
671 }
672 }
673}
674
675#[cfg(test)]
676mod tests {
677 use alloc::string::{String, ToString};
678 use core::iter::FromIterator;
679 use super::{InlinableString, StringExt, INLINE_STRING_CAPACITY};
680 use core::cmp::Ordering;
681 use core::str::FromStr;
682
683 #[test]
684 fn test_size() {
685 use core::mem::size_of;
686 assert_eq!(size_of::<InlinableString>(), 4 * size_of::<usize>());
687 }
688
689 #[test]
693 fn test_push_str() {
694 let mut s = InlinableString::new();
695 s.push_str("small");
696 assert_eq!(s, "small");
697
698 let long_str = "this is a really long string that is much larger than
699 INLINE_STRING_CAPACITY and so cannot be stored inline.";
700 s.push_str(long_str);
701 assert_eq!(s, String::from("small") + long_str);
702 }
703
704 #[test]
705 fn test_write() {
706 use core::fmt::Write;
707 let mut s = InlinableString::new();
708 write!(&mut s, "small").expect("!write");
709 assert_eq!(s, "small");
710
711 let long_str = "this is a really long string that is much larger than
712 INLINE_STRING_CAPACITY and so cannot be stored inline.";
713 write!(&mut s, "{}", long_str).expect("!write");
714 assert_eq!(s, String::from("small") + long_str);
715 }
716
717 #[test]
718 fn test_push() {
719 let mut s = InlinableString::new();
720
721 for _ in 0..INLINE_STRING_CAPACITY {
722 s.push('a');
723 }
724 s.push('a');
725
726 assert_eq!(
727 s,
728 String::from_iter((0..INLINE_STRING_CAPACITY + 1).map(|_| 'a'))
729 );
730 }
731
732 #[test]
733 fn test_insert() {
734 let mut s = InlinableString::new();
735
736 for _ in 0..INLINE_STRING_CAPACITY {
737 s.insert(0, 'a');
738 }
739 s.insert(0, 'a');
740
741 assert_eq!(
742 s,
743 String::from_iter((0..INLINE_STRING_CAPACITY + 1).map(|_| 'a'))
744 );
745 }
746
747 #[test]
748 fn test_insert_str() {
749 let mut s = InlinableString::new();
750
751 for _ in 0..(INLINE_STRING_CAPACITY / 3) {
752 s.insert_str(0, "foo");
753 }
754 s.insert_str(0, "foo");
755
756 assert_eq!(
757 s,
758 String::from_iter((0..(INLINE_STRING_CAPACITY / 3) + 1).map(|_| "foo"))
759 );
760 }
761
762 #[test]
765 fn test_new() {
766 let s = <InlinableString as StringExt>::new();
767 assert!(StringExt::is_empty(&s));
768 }
769
770 #[test]
771 fn test_with_capacity() {
772 let s = <InlinableString as StringExt>::with_capacity(10);
773 assert!(StringExt::capacity(&s) >= 10);
774 }
775
776 #[test]
777 fn test_from_utf8() {
778 let s = <InlinableString as StringExt>::from_utf8(vec![104, 101, 108, 108, 111]);
779 assert_eq!(s.unwrap(), "hello");
780 }
781
782 #[test]
783 fn test_from_utf16() {
784 let v = &mut [0xD834, 0xDD1E, 0x006d, 0x0075, 0x0073, 0x0069, 0x0063];
785 let s = <InlinableString as StringExt>::from_utf16(v);
786 assert_eq!(s.unwrap(), "𝄞music");
787 }
788
789 #[test]
790 fn test_from_utf16_lossy() {
791 let input = b"Hello \xF0\x90\x80World";
792 let output = <InlinableString as StringExt>::from_utf8_lossy(input);
793 assert_eq!(output, "Hello \u{FFFD}World");
794 }
795
796 #[test]
797 fn test_into_bytes() {
798 let s = InlinableString::from("hello");
799 let bytes = StringExt::into_bytes(s);
800 assert_eq!(bytes, [104, 101, 108, 108, 111]);
801 }
802
803 #[test]
804 fn test_capacity() {
805 let s = <InlinableString as StringExt>::with_capacity(100);
806 assert!(InlinableString::capacity(&s) >= 100);
807 }
808
809 #[test]
810 fn test_reserve() {
811 let mut s = <InlinableString as StringExt>::new();
812 StringExt::reserve(&mut s, 100);
813 assert!(InlinableString::capacity(&s) >= 100);
814 }
815
816 #[test]
817 fn test_reserve_exact() {
818 let mut s = <InlinableString as StringExt>::new();
819 StringExt::reserve_exact(&mut s, 100);
820 assert!(InlinableString::capacity(&s) >= 100);
821 }
822
823 #[test]
824 fn test_shrink_to_fit() {
825 let mut s = <InlinableString as StringExt>::with_capacity(100);
826 StringExt::push_str(&mut s, "foo");
827 StringExt::shrink_to_fit(&mut s);
828 assert_eq!(InlinableString::capacity(&s), INLINE_STRING_CAPACITY);
829 }
830
831 #[test]
832 fn test_truncate() {
833 let mut s = InlinableString::from("foo");
834 StringExt::truncate(&mut s, 1);
835 assert_eq!(s, "f");
836 }
837
838 #[test]
839 fn test_pop() {
840 let mut s = InlinableString::from("foo");
841 assert_eq!(StringExt::pop(&mut s), Some('o'));
842 assert_eq!(StringExt::pop(&mut s), Some('o'));
843 assert_eq!(StringExt::pop(&mut s), Some('f'));
844 assert_eq!(StringExt::pop(&mut s), None);
845 }
846
847 #[test]
848 fn test_ord() {
849 let s1 = InlinableString::from("foo");
850 let s2 = InlinableString::from("bar");
851 assert_eq!(Ord::cmp(&s1, &s2), Ordering::Greater);
852 assert_eq!(Ord::cmp(&s1, &s1), Ordering::Equal);
853 }
854
855 #[test]
856 fn test_display() {
857 let short = InlinableString::from("he");
858 let long = InlinableString::from("hello world");
859 assert_eq!(format!("{}", short), "he".to_string());
860 assert_eq!(format!("{}", long), "hello world".to_string());
861 }
862
863 #[test]
864 fn test_debug() {
865 let short = InlinableString::from("he");
866 let long = InlinableString::from("hello world hello world hello world");
867 assert_eq!(format!("{:?}", short), "\"he\"");
868 assert_eq!(
869 format!("{:?}", long),
870 "\"hello world hello world hello world\""
871 );
872 }
873
874 fn parse_non_empty<T: FromStr>(s: &str) -> Option<T> {
876 if s.len() == 0 {
877 None
878 } else {
879 let val = T::from_str(s).unwrap_or_else(|_| panic!("unwrap"));
880 Some(val)
881 }
882 }
883
884 #[test]
885 fn test_fromstr() {
886 assert_eq!(parse_non_empty::<InlinableString>(""), None);
887 assert_eq!(parse_non_empty::<u8>("10"), Some(10u8));
888 assert_eq!(
889 parse_non_empty::<InlinableString>("foo"),
890 Some(InlinableString::from("foo"))
891 );
892 }
893}
894
895#[cfg(test)]
896#[cfg(feature = "nightly")]
897mod benches {
898 #[cfg(feature = "no_std")]
899 use alloc::string::String;
900 use super::{InlinableString, StringExt};
901 use test::{black_box, Bencher};
902
903 const SMALL_STR: &'static str = "foobar";
904
905 const LARGE_STR: &'static str =
906 "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
907 abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
908 abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
909 abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
910 abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
911 abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
912 abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
913 abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
914
915 #[bench]
916 fn bench_std_string_push_str_small_onto_empty(b: &mut Bencher) {
917 b.iter(|| {
918 let mut s = String::new();
919 s.push_str(SMALL_STR);
920 black_box(s);
921 });
922 }
923
924 #[bench]
925 fn bench_inlinable_string_push_str_small_onto_empty(b: &mut Bencher) {
926 b.iter(|| {
927 let mut s = InlinableString::new();
928 s.push_str(SMALL_STR);
929 black_box(s);
930 });
931 }
932
933 #[bench]
934 fn bench_std_string_push_str_large_onto_empty(b: &mut Bencher) {
935 b.iter(|| {
936 let mut s = String::new();
937 s.push_str(LARGE_STR);
938 black_box(s);
939 });
940 }
941
942 #[bench]
943 fn bench_inlinable_string_push_str_large_onto_empty(b: &mut Bencher) {
944 b.iter(|| {
945 let mut s = InlinableString::new();
946 s.push_str(LARGE_STR);
947 black_box(s);
948 });
949 }
950
951 #[bench]
952 fn bench_std_string_push_str_small_onto_small(b: &mut Bencher) {
953 b.iter(|| {
954 let mut s = String::from(SMALL_STR);
955 s.push_str(SMALL_STR);
956 black_box(s);
957 });
958 }
959
960 #[bench]
961 fn bench_inlinable_string_push_str_small_onto_small(b: &mut Bencher) {
962 b.iter(|| {
963 let mut s = InlinableString::from(SMALL_STR);
964 s.push_str(SMALL_STR);
965 black_box(s);
966 });
967 }
968
969 #[bench]
970 fn bench_std_string_push_str_large_onto_large(b: &mut Bencher) {
971 b.iter(|| {
972 let mut s = String::from(LARGE_STR);
973 s.push_str(LARGE_STR);
974 black_box(s);
975 });
976 }
977
978 #[bench]
979 fn bench_inlinable_string_push_str_large_onto_large(b: &mut Bencher) {
980 b.iter(|| {
981 let mut s = InlinableString::from(LARGE_STR);
982 s.push_str(LARGE_STR);
983 black_box(s);
984 });
985 }
986
987 #[bench]
988 fn bench_std_string_from_small(b: &mut Bencher) {
989 b.iter(|| {
990 let s = String::from(SMALL_STR);
991 black_box(s);
992 });
993 }
994
995 #[bench]
996 fn bench_inlinable_string_from_small(b: &mut Bencher) {
997 b.iter(|| {
998 let s = InlinableString::from(SMALL_STR);
999 black_box(s);
1000 });
1001 }
1002
1003 #[bench]
1004 fn bench_std_string_from_large(b: &mut Bencher) {
1005 b.iter(|| {
1006 let s = String::from(LARGE_STR);
1007 black_box(s);
1008 });
1009 }
1010
1011 #[bench]
1012 fn bench_inlinable_string_from_large(b: &mut Bencher) {
1013 b.iter(|| {
1014 let s = InlinableString::from(LARGE_STR);
1015 black_box(s);
1016 });
1017 }
1018}