1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 // ignore-lexer-test FIXME #15679
13 //! An owned, growable string that enforces that its contents are valid UTF-8.
17 use core::default::Default;
23 use {Collection, Mutable, MutableSeq};
26 use str::{CharRange, StrAllocating, MaybeOwned, Owned, Slice};
29 /// A growable string stored as a UTF-8 encoded buffer.
30 #[deriving(Clone, PartialEq, PartialOrd, Eq, Ord)]
36 /// Creates a new string buffer initialized with the empty string.
38 pub fn new() -> String {
44 /// Creates a new string buffer with the given capacity.
46 pub fn with_capacity(capacity: uint) -> String {
48 vec: Vec::with_capacity(capacity),
52 /// Creates a new string buffer from length, capacity, and a pointer.
54 pub unsafe fn from_raw_parts(length: uint, capacity: uint, ptr: *mut u8) -> String {
56 vec: Vec::from_raw_parts(length, capacity, ptr),
60 /// Creates a new string buffer from the given string.
62 pub fn from_str(string: &str) -> String {
64 vec: Vec::from_slice(string.as_bytes())
69 #[deprecated = "obsoleted by the removal of ~str"]
71 pub fn from_owned_str(string: String) -> String {
75 /// Returns the vector as a string buffer, if possible, taking care not to
78 /// Returns `Err` with the original vector if the vector contains invalid
84 /// let hello_vec = vec![104, 101, 108, 108, 111];
85 /// let string = String::from_utf8(hello_vec);
86 /// assert_eq!(string, Ok("hello".to_string()));
89 pub fn from_utf8(vec: Vec<u8>) -> Result<String, Vec<u8>> {
90 if str::is_utf8(vec.as_slice()) {
91 Ok(String { vec: vec })
97 /// Converts a vector of bytes to a new utf-8 string.
98 /// Any invalid utf-8 sequences are replaced with U+FFFD REPLACEMENT CHARACTER.
103 /// let input = b"Hello \xF0\x90\x80World";
104 /// let output = String::from_utf8_lossy(input);
105 /// assert_eq!(output.as_slice(), "Hello \uFFFDWorld");
107 pub fn from_utf8_lossy<'a>(v: &'a [u8]) -> MaybeOwned<'a> {
109 return Slice(unsafe { mem::transmute(v) })
112 static TAG_CONT_U8: u8 = 128u8;
113 static REPLACEMENT: &'static [u8] = b"\xEF\xBF\xBD"; // U+FFFD in UTF-8
116 fn unsafe_get(xs: &[u8], i: uint) -> u8 {
117 unsafe { *xs.unsafe_ref(i) }
119 fn safe_get(xs: &[u8], i: uint, total: uint) -> u8 {
127 let mut res = String::with_capacity(total);
131 res.push_bytes(v.slice_to(i))
135 // subseqidx is the index of the first byte of the subsequence we're looking at.
136 // It's used to copy a bunch of contiguous good codepoints at once instead of copying
138 let mut subseqidx = 0;
142 let byte = unsafe_get(v, i);
145 macro_rules! error(() => ({
148 res.push_bytes(v.slice(subseqidx, i_));
151 res.push_bytes(REPLACEMENT);
156 // subseqidx handles this
158 let w = str::utf8_char_width(byte);
162 if safe_get(v, i, total) & 192u8 != TAG_CONT_U8 {
169 match (byte, safe_get(v, i, total)) {
170 (0xE0 , 0xA0 .. 0xBF) => (),
171 (0xE1 .. 0xEC, 0x80 .. 0xBF) => (),
172 (0xED , 0x80 .. 0x9F) => (),
173 (0xEE .. 0xEF, 0x80 .. 0xBF) => (),
180 if safe_get(v, i, total) & 192u8 != TAG_CONT_U8 {
187 match (byte, safe_get(v, i, total)) {
188 (0xF0 , 0x90 .. 0xBF) => (),
189 (0xF1 .. 0xF3, 0x80 .. 0xBF) => (),
190 (0xF4 , 0x80 .. 0x8F) => (),
197 if safe_get(v, i, total) & 192u8 != TAG_CONT_U8 {
202 if safe_get(v, i, total) & 192u8 != TAG_CONT_U8 {
215 if subseqidx < total {
217 res.push_bytes(v.slice(subseqidx, total))
220 Owned(res.into_string())
223 /// Decode a UTF-16 encoded vector `v` into a `String`, returning `None`
224 /// if `v` contains any invalid data.
230 /// let mut v = [0xD834, 0xDD1E, 0x006d, 0x0075,
231 /// 0x0073, 0x0069, 0x0063];
232 /// assert_eq!(String::from_utf16(v), Some("𝄞music".to_string()));
234 /// // 𝄞mu<invalid>ic
236 /// assert_eq!(String::from_utf16(v), None);
238 pub fn from_utf16(v: &[u16]) -> Option<String> {
239 let mut s = String::with_capacity(v.len() / 2);
240 for c in str::utf16_items(v) {
242 str::ScalarValue(c) => s.push_char(c),
243 str::LoneSurrogate(_) => return None
249 /// Decode a UTF-16 encoded vector `v` into a string, replacing
250 /// invalid data with the replacement character (U+FFFD).
254 /// // 𝄞mus<invalid>ic<invalid>
255 /// let v = [0xD834, 0xDD1E, 0x006d, 0x0075,
256 /// 0x0073, 0xDD1E, 0x0069, 0x0063,
259 /// assert_eq!(String::from_utf16_lossy(v),
260 /// "𝄞mus\uFFFDic\uFFFD".to_string());
262 pub fn from_utf16_lossy(v: &[u16]) -> String {
263 str::utf16_items(v).map(|c| c.to_char_lossy()).collect()
266 /// Convert a vector of chars to a string
271 /// let chars = ['h', 'e', 'l', 'l', 'o'];
272 /// let string = String::from_chars(chars);
273 /// assert_eq!(string.as_slice(), "hello");
276 pub fn from_chars(chs: &[char]) -> String {
277 chs.iter().map(|c| *c).collect()
280 /// Return the underlying byte buffer, encoded as UTF-8.
282 pub fn into_bytes(self) -> Vec<u8> {
286 /// Pushes the given string onto this buffer; then, returns `self` so that it can be used
289 pub fn append(mut self, second: &str) -> String {
290 self.push_str(second);
294 /// Creates a string buffer by repeating a character `length` times.
296 pub fn from_char(length: uint, ch: char) -> String {
301 let mut buf = String::new();
303 let size = buf.len() * length;
305 for _ in range(1, length) {
311 /// Convert a byte to a UTF-8 string
315 /// Fails if invalid UTF-8
320 /// let string = String::from_byte(104);
321 /// assert_eq!(string.as_slice(), "h");
323 pub fn from_byte(b: u8) -> String {
325 String::from_char(1, b as char)
328 /// Pushes the given string onto this string buffer.
330 pub fn push_str(&mut self, string: &str) {
331 self.vec.push_all(string.as_bytes())
334 /// Push `ch` onto the given string `count` times.
336 pub fn grow(&mut self, count: uint, ch: char) {
337 for _ in range(0, count) {
342 /// Returns the number of bytes that this string buffer can hold without reallocating.
344 pub fn byte_capacity(&self) -> uint {
348 /// Reserves capacity for at least `extra` additional bytes in this string buffer.
350 pub fn reserve_additional(&mut self, extra: uint) {
351 self.vec.reserve_additional(extra)
354 /// Reserves capacity for at least `capacity` bytes in this string buffer.
356 pub fn reserve(&mut self, capacity: uint) {
357 self.vec.reserve(capacity)
360 /// Reserves capacity for exactly `capacity` bytes in this string buffer.
362 pub fn reserve_exact(&mut self, capacity: uint) {
363 self.vec.reserve_exact(capacity)
366 /// Shrinks the capacity of this string buffer to match its length.
368 pub fn shrink_to_fit(&mut self) {
369 self.vec.shrink_to_fit()
372 /// Adds the given character to the end of the string.
374 pub fn push_char(&mut self, ch: char) {
375 let cur_len = self.len();
376 // This may use up to 4 bytes.
377 self.vec.reserve_additional(4);
380 // Attempt to not use an intermediate buffer by just pushing bytes
381 // directly onto this string.
383 data: self.vec.as_ptr().offset(cur_len as int),
386 let used = ch.encode_utf8(mem::transmute(slice));
387 self.vec.set_len(cur_len + used);
391 /// Pushes the given bytes onto this string buffer. This is unsafe because it does not check
392 /// to ensure that the resulting string will be valid UTF-8.
394 pub unsafe fn push_bytes(&mut self, bytes: &[u8]) {
395 self.vec.push_all(bytes)
398 /// Works with the underlying buffer as a byte slice.
400 pub fn as_bytes<'a>(&'a self) -> &'a [u8] {
404 /// Works with the underlying buffer as a mutable byte slice. Unsafe
405 /// because this can be used to violate the UTF-8 property.
407 pub unsafe fn as_mut_bytes<'a>(&'a mut self) -> &'a mut [u8] {
408 self.vec.as_mut_slice()
411 /// Shorten a string to the specified length (which must be <= the current length)
413 pub fn truncate(&mut self, len: uint) {
414 assert!(self.as_slice().is_char_boundary(len));
415 self.vec.truncate(len)
418 /// Appends a byte to this string buffer. The caller must preserve the valid UTF-8 property.
420 pub unsafe fn push_byte(&mut self, byte: u8) {
424 /// Removes the last byte from the string buffer and returns it. Returns `None` if this string
427 /// The caller must preserve the valid UTF-8 property.
429 pub unsafe fn pop_byte(&mut self) -> Option<u8> {
430 let len = self.len();
435 let byte = self.as_bytes()[len - 1];
436 self.vec.set_len(len - 1);
440 /// Removes the last character from the string buffer and returns it. Returns `None` if this
441 /// string buffer is empty.
443 pub fn pop_char(&mut self) -> Option<char> {
444 let len = self.len();
449 let CharRange {ch, next} = self.as_slice().char_range_at_reverse(len);
451 self.vec.set_len(next);
456 /// Removes the first byte from the string buffer and returns it. Returns `None` if this string
459 /// The caller must preserve the valid UTF-8 property.
460 pub unsafe fn shift_byte(&mut self) -> Option<u8> {
464 /// Removes the first character from the string buffer and returns it. Returns `None` if this
465 /// string buffer is empty.
469 /// This is a O(n) operation as it requires copying every element in the buffer.
470 pub fn shift_char (&mut self) -> Option<char> {
471 let len = self.len();
476 let CharRange {ch, next} = self.as_slice().char_range_at(0);
477 let new_len = len - next;
479 ptr::copy_memory(self.vec.as_mut_ptr(), self.vec.as_ptr().offset(next as int), new_len);
480 self.vec.set_len(new_len);
485 /// Views the string buffer as a mutable sequence of bytes.
487 /// Callers must preserve the valid UTF-8 property.
488 pub unsafe fn as_mut_vec<'a>(&'a mut self) -> &'a mut Vec<u8> {
493 impl Collection for String {
495 fn len(&self) -> uint {
500 impl Mutable for String {
502 fn clear(&mut self) {
507 impl FromIterator<char> for String {
508 fn from_iter<I:Iterator<char>>(iterator: I) -> String {
509 let mut buf = String::new();
510 buf.extend(iterator);
515 impl Extendable<char> for String {
516 fn extend<I:Iterator<char>>(&mut self, mut iterator: I) {
523 impl Str for String {
525 fn as_slice<'a>(&'a self) -> &'a str {
527 mem::transmute(self.vec.as_slice())
532 impl StrAllocating for String {
534 fn into_string(self) -> String {
539 impl Default for String {
540 fn default() -> String {
545 impl fmt::Show for String {
546 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
547 self.as_slice().fmt(f)
551 impl<H: hash::Writer> hash::Hash<H> for String {
553 fn hash(&self, hasher: &mut H) {
554 self.as_slice().hash(hasher)
558 impl<'a, S: Str> Equiv<S> for String {
560 fn equiv(&self, other: &S) -> bool {
561 self.as_slice() == other.as_slice()
565 impl<S: Str> Add<S, String> for String {
566 fn add(&self, other: &S) -> String {
567 let mut s = String::from_str(self.as_slice());
568 s.push_str(other.as_slice());
577 /// Converts a vector of bytes to a new `String` without checking if
578 /// it contains valid UTF-8. This is unsafe because it assumes that
579 /// the utf-8-ness of the vector has already been validated.
581 pub unsafe fn from_utf8(bytes: Vec<u8>) -> String {
582 String { vec: bytes }
591 use {Mutable, MutableSeq};
593 use str::{Str, StrSlice, Owned, Slice};
599 let owned: Option<::std::string::String> = from_str("string");
600 assert_eq!(owned.as_ref().map(|s| s.as_slice()), Some("string"));
604 fn test_from_utf8() {
605 let xs = Vec::from_slice(b"hello");
606 assert_eq!(String::from_utf8(xs), Ok(String::from_str("hello")));
608 let xs = Vec::from_slice("ศไทย中华Việt Nam".as_bytes());
609 assert_eq!(String::from_utf8(xs), Ok(String::from_str("ศไทย中华Việt Nam")));
611 let xs = Vec::from_slice(b"hello\xFF");
612 assert_eq!(String::from_utf8(xs),
613 Err(Vec::from_slice(b"hello\xFF")));
617 fn test_from_utf8_lossy() {
619 assert_eq!(String::from_utf8_lossy(xs), Slice("hello"));
621 let xs = "ศไทย中华Việt Nam".as_bytes();
622 assert_eq!(String::from_utf8_lossy(xs), Slice("ศไทย中华Việt Nam"));
624 let xs = b"Hello\xC2 There\xFF Goodbye";
625 assert_eq!(String::from_utf8_lossy(xs),
626 Owned(String::from_str("Hello\uFFFD There\uFFFD Goodbye")));
628 let xs = b"Hello\xC0\x80 There\xE6\x83 Goodbye";
629 assert_eq!(String::from_utf8_lossy(xs),
630 Owned(String::from_str("Hello\uFFFD\uFFFD There\uFFFD Goodbye")));
632 let xs = b"\xF5foo\xF5\x80bar";
633 assert_eq!(String::from_utf8_lossy(xs),
634 Owned(String::from_str("\uFFFDfoo\uFFFD\uFFFDbar")));
636 let xs = b"\xF1foo\xF1\x80bar\xF1\x80\x80baz";
637 assert_eq!(String::from_utf8_lossy(xs),
638 Owned(String::from_str("\uFFFDfoo\uFFFDbar\uFFFDbaz")));
640 let xs = b"\xF4foo\xF4\x80bar\xF4\xBFbaz";
641 assert_eq!(String::from_utf8_lossy(xs),
642 Owned(String::from_str("\uFFFDfoo\uFFFDbar\uFFFD\uFFFDbaz")));
644 let xs = b"\xF0\x80\x80\x80foo\xF0\x90\x80\x80bar";
645 assert_eq!(String::from_utf8_lossy(xs), Owned(String::from_str("\uFFFD\uFFFD\uFFFD\uFFFD\
646 foo\U00010000bar")));
649 let xs = b"\xED\xA0\x80foo\xED\xBF\xBFbar";
650 assert_eq!(String::from_utf8_lossy(xs), Owned(String::from_str("\uFFFD\uFFFD\uFFFDfoo\
651 \uFFFD\uFFFD\uFFFDbar")));
655 fn test_from_utf16() {
657 [(String::from_str("𐍅𐌿𐌻𐍆𐌹𐌻𐌰\n"),
658 vec![0xd800_u16, 0xdf45_u16, 0xd800_u16, 0xdf3f_u16,
659 0xd800_u16, 0xdf3b_u16, 0xd800_u16, 0xdf46_u16,
660 0xd800_u16, 0xdf39_u16, 0xd800_u16, 0xdf3b_u16,
661 0xd800_u16, 0xdf30_u16, 0x000a_u16]),
663 (String::from_str("𐐒𐑉𐐮𐑀𐐲𐑋 𐐏𐐲𐑍\n"),
664 vec![0xd801_u16, 0xdc12_u16, 0xd801_u16,
665 0xdc49_u16, 0xd801_u16, 0xdc2e_u16, 0xd801_u16,
666 0xdc40_u16, 0xd801_u16, 0xdc32_u16, 0xd801_u16,
667 0xdc4b_u16, 0x0020_u16, 0xd801_u16, 0xdc0f_u16,
668 0xd801_u16, 0xdc32_u16, 0xd801_u16, 0xdc4d_u16,
671 (String::from_str("𐌀𐌖𐌋𐌄𐌑𐌉·𐌌𐌄𐌕𐌄𐌋𐌉𐌑\n"),
672 vec![0xd800_u16, 0xdf00_u16, 0xd800_u16, 0xdf16_u16,
673 0xd800_u16, 0xdf0b_u16, 0xd800_u16, 0xdf04_u16,
674 0xd800_u16, 0xdf11_u16, 0xd800_u16, 0xdf09_u16,
675 0x00b7_u16, 0xd800_u16, 0xdf0c_u16, 0xd800_u16,
676 0xdf04_u16, 0xd800_u16, 0xdf15_u16, 0xd800_u16,
677 0xdf04_u16, 0xd800_u16, 0xdf0b_u16, 0xd800_u16,
678 0xdf09_u16, 0xd800_u16, 0xdf11_u16, 0x000a_u16 ]),
680 (String::from_str("𐒋𐒘𐒈𐒑𐒛𐒒 𐒕𐒓 𐒈𐒚𐒍 𐒏𐒜𐒒𐒖𐒆 𐒕𐒆\n"),
681 vec![0xd801_u16, 0xdc8b_u16, 0xd801_u16, 0xdc98_u16,
682 0xd801_u16, 0xdc88_u16, 0xd801_u16, 0xdc91_u16,
683 0xd801_u16, 0xdc9b_u16, 0xd801_u16, 0xdc92_u16,
684 0x0020_u16, 0xd801_u16, 0xdc95_u16, 0xd801_u16,
685 0xdc93_u16, 0x0020_u16, 0xd801_u16, 0xdc88_u16,
686 0xd801_u16, 0xdc9a_u16, 0xd801_u16, 0xdc8d_u16,
687 0x0020_u16, 0xd801_u16, 0xdc8f_u16, 0xd801_u16,
688 0xdc9c_u16, 0xd801_u16, 0xdc92_u16, 0xd801_u16,
689 0xdc96_u16, 0xd801_u16, 0xdc86_u16, 0x0020_u16,
690 0xd801_u16, 0xdc95_u16, 0xd801_u16, 0xdc86_u16,
692 // Issue #12318, even-numbered non-BMP planes
693 (String::from_str("\U00020000"),
694 vec![0xD840, 0xDC00])];
696 for p in pairs.iter() {
697 let (s, u) = (*p).clone();
698 let s_as_utf16 = s.as_slice().utf16_units().collect::<Vec<u16>>();
699 let u_as_string = String::from_utf16(u.as_slice()).unwrap();
701 assert!(str::is_utf16(u.as_slice()));
702 assert_eq!(s_as_utf16, u);
704 assert_eq!(u_as_string, s);
705 assert_eq!(String::from_utf16_lossy(u.as_slice()), s);
707 assert_eq!(String::from_utf16(s_as_utf16.as_slice()).unwrap(), s);
708 assert_eq!(u_as_string.as_slice().utf16_units().collect::<Vec<u16>>(), u);
713 fn test_utf16_invalid() {
714 // completely positive cases tested above.
716 assert_eq!(String::from_utf16([0xD800]), None);
718 assert_eq!(String::from_utf16([0xD800, 0xD800]), None);
721 assert_eq!(String::from_utf16([0x0061, 0xDC00]), None);
724 assert_eq!(String::from_utf16([0xD800, 0xd801, 0xdc8b, 0xD800]), None);
728 fn test_from_utf16_lossy() {
729 // completely positive cases tested above.
731 assert_eq!(String::from_utf16_lossy([0xD800]), String::from_str("\uFFFD"));
733 assert_eq!(String::from_utf16_lossy([0xD800, 0xD800]), String::from_str("\uFFFD\uFFFD"));
736 assert_eq!(String::from_utf16_lossy([0x0061, 0xDC00]), String::from_str("a\uFFFD"));
739 assert_eq!(String::from_utf16_lossy([0xD800, 0xd801, 0xdc8b, 0xD800]),
740 String::from_str("\uFFFD𐒋\uFFFD"));
744 fn test_push_bytes() {
745 let mut s = String::from_str("ABC");
747 s.push_bytes([ 'D' as u8 ]);
749 assert_eq!(s.as_slice(), "ABCD");
754 let mut s = String::new();
756 assert_eq!(s.as_slice().slice_from(0), "");
758 assert_eq!(s.as_slice().slice_from(0), "abc");
759 s.push_str("ประเทศไทย中华Việt Nam");
760 assert_eq!(s.as_slice().slice_from(0), "abcประเทศไทย中华Việt Nam");
764 fn test_push_char() {
765 let mut data = String::from_str("ประเทศไทย中");
767 data.push_char('b'); // 1 byte
768 data.push_char('¢'); // 2 byte
769 data.push_char('€'); // 3 byte
770 data.push_char('𤭢'); // 4 byte
771 assert_eq!(data.as_slice(), "ประเทศไทย中华b¢€𤭢");
776 let mut data = String::from_str("ประเทศไทย中华b¢€𤭢");
777 assert_eq!(data.pop_char().unwrap(), '𤭢'); // 4 bytes
778 assert_eq!(data.pop_char().unwrap(), '€'); // 3 bytes
779 assert_eq!(data.pop_char().unwrap(), '¢'); // 2 bytes
780 assert_eq!(data.pop_char().unwrap(), 'b'); // 1 bytes
781 assert_eq!(data.pop_char().unwrap(), '华');
782 assert_eq!(data.as_slice(), "ประเทศไทย中");
786 fn test_shift_char() {
787 let mut data = String::from_str("𤭢€¢b华ประเทศไทย中");
788 assert_eq!(data.shift_char().unwrap(), '𤭢'); // 4 bytes
789 assert_eq!(data.shift_char().unwrap(), '€'); // 3 bytes
790 assert_eq!(data.shift_char().unwrap(), '¢'); // 2 bytes
791 assert_eq!(data.shift_char().unwrap(), 'b'); // 1 bytes
792 assert_eq!(data.shift_char().unwrap(), '华');
793 assert_eq!(data.as_slice(), "ประเทศไทย中");
797 fn test_str_truncate() {
798 let mut s = String::from_str("12345");
800 assert_eq!(s.as_slice(), "12345");
802 assert_eq!(s.as_slice(), "123");
804 assert_eq!(s.as_slice(), "");
806 let mut s = String::from_str("12345");
807 let p = s.as_slice().as_ptr();
810 let p_ = s.as_slice().as_ptr();
816 fn test_str_truncate_invalid_len() {
817 let mut s = String::from_str("12345");
823 fn test_str_truncate_split_codepoint() {
824 let mut s = String::from_str("\u00FC"); // ü
829 fn test_str_clear() {
830 let mut s = String::from_str("12345");
832 assert_eq!(s.len(), 0);
833 assert_eq!(s.as_slice(), "");
838 let a = String::from_str("12345");
840 let b = b + String::from_str("2");
841 assert_eq!(b.len(), 7);
842 assert_eq!(b.as_slice(), "1234522");
846 fn bench_with_capacity(b: &mut Bencher) {
848 String::with_capacity(100)
853 fn bench_push_str(b: &mut Bencher) {
854 let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
856 let mut r = String::new();
862 fn from_utf8_lossy_100_ascii(b: &mut Bencher) {
863 let s = b"Hello there, the quick brown fox jumped over the lazy dog! \
864 Lorem ipsum dolor sit amet, consectetur. ";
866 assert_eq!(100, s.len());
868 let _ = String::from_utf8_lossy(s);
873 fn from_utf8_lossy_100_multibyte(b: &mut Bencher) {
874 let s = "𐌀𐌖𐌋𐌄𐌑𐌉ปรدولة الكويتทศไทย中华𐍅𐌿𐌻𐍆𐌹𐌻𐌰".as_bytes();
875 assert_eq!(100, s.len());
877 let _ = String::from_utf8_lossy(s);
882 fn from_utf8_lossy_invalid(b: &mut Bencher) {
883 let s = b"Hello\xC0\x80 There\xE6\x83 Goodbye";
885 let _ = String::from_utf8_lossy(s);
890 fn from_utf8_lossy_100_invalid(b: &mut Bencher) {
891 let s = Vec::from_elem(100, 0xF5u8);
893 let _ = String::from_utf8_lossy(s.as_slice());