]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys_common/wtf8.rs
Rollup merge of #70038 - DutchGhost:const-forget-tests, r=RalfJung
[rust.git] / src / libstd / sys_common / wtf8.rs
1 //! Implementation of [the WTF-8 encoding](https://simonsapin.github.io/wtf-8/).
2 //!
3 //! This library uses Rust’s type system to maintain
4 //! [well-formedness](https://simonsapin.github.io/wtf-8/#well-formed),
5 //! like the `String` and `&str` types do for UTF-8.
6 //!
7 //! Since [WTF-8 must not be used
8 //! for interchange](https://simonsapin.github.io/wtf-8/#intended-audience),
9 //! this library deliberately does not provide access to the underlying bytes
10 //! of WTF-8 strings,
11 //! nor can it decode WTF-8 from arbitrary bytes.
12 //! WTF-8 strings can be obtained from UTF-8, UTF-16, or code points.
13
14 // this module is imported from @SimonSapin's repo and has tons of dead code on
15 // unix (it's mostly used on windows), so don't worry about dead code here.
16 #![allow(dead_code)]
17
18 use core::str::next_code_point;
19
20 use crate::borrow::Cow;
21 use crate::char;
22 use crate::fmt;
23 use crate::hash::{Hash, Hasher};
24 use crate::iter::FromIterator;
25 use crate::mem;
26 use crate::ops;
27 use crate::rc::Rc;
28 use crate::slice;
29 use crate::str;
30 use crate::sync::Arc;
31 use crate::sys_common::AsInner;
32
33 const UTF8_REPLACEMENT_CHARACTER: &str = "\u{FFFD}";
34
35 /// A Unicode code point: from U+0000 to U+10FFFF.
36 ///
37 /// Compares with the `char` type,
38 /// which represents a Unicode scalar value:
39 /// a code point that is not a surrogate (U+D800 to U+DFFF).
40 #[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
41 pub struct CodePoint {
42     value: u32,
43 }
44
45 /// Format the code point as `U+` followed by four to six hexadecimal digits.
46 /// Example: `U+1F4A9`
47 impl fmt::Debug for CodePoint {
48     #[inline]
49     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
50         write!(formatter, "U+{:04X}", self.value)
51     }
52 }
53
54 impl CodePoint {
55     /// Unsafely creates a new `CodePoint` without checking the value.
56     ///
57     /// Only use when `value` is known to be less than or equal to 0x10FFFF.
58     #[inline]
59     pub unsafe fn from_u32_unchecked(value: u32) -> CodePoint {
60         CodePoint { value }
61     }
62
63     /// Creates a new `CodePoint` if the value is a valid code point.
64     ///
65     /// Returns `None` if `value` is above 0x10FFFF.
66     #[inline]
67     pub fn from_u32(value: u32) -> Option<CodePoint> {
68         match value {
69             0..=0x10FFFF => Some(CodePoint { value }),
70             _ => None,
71         }
72     }
73
74     /// Creates a new `CodePoint` from a `char`.
75     ///
76     /// Since all Unicode scalar values are code points, this always succeeds.
77     #[inline]
78     pub fn from_char(value: char) -> CodePoint {
79         CodePoint { value: value as u32 }
80     }
81
82     /// Returns the numeric value of the code point.
83     #[inline]
84     pub fn to_u32(&self) -> u32 {
85         self.value
86     }
87
88     /// Optionally returns a Unicode scalar value for the code point.
89     ///
90     /// Returns `None` if the code point is a surrogate (from U+D800 to U+DFFF).
91     #[inline]
92     pub fn to_char(&self) -> Option<char> {
93         match self.value {
94             0xD800..=0xDFFF => None,
95             _ => Some(unsafe { char::from_u32_unchecked(self.value) }),
96         }
97     }
98
99     /// Returns a Unicode scalar value for the code point.
100     ///
101     /// Returns `'\u{FFFD}'` (the replacement character “�”)
102     /// if the code point is a surrogate (from U+D800 to U+DFFF).
103     #[inline]
104     pub fn to_char_lossy(&self) -> char {
105         self.to_char().unwrap_or('\u{FFFD}')
106     }
107 }
108
109 /// An owned, growable string of well-formed WTF-8 data.
110 ///
111 /// Similar to `String`, but can additionally contain surrogate code points
112 /// if they’re not in a surrogate pair.
113 #[derive(Eq, PartialEq, Ord, PartialOrd, Clone)]
114 pub struct Wtf8Buf {
115     bytes: Vec<u8>,
116 }
117
118 impl ops::Deref for Wtf8Buf {
119     type Target = Wtf8;
120
121     fn deref(&self) -> &Wtf8 {
122         self.as_slice()
123     }
124 }
125
126 impl ops::DerefMut for Wtf8Buf {
127     fn deref_mut(&mut self) -> &mut Wtf8 {
128         self.as_mut_slice()
129     }
130 }
131
132 /// Format the string with double quotes,
133 /// and surrogates as `\u` followed by four hexadecimal digits.
134 /// Example: `"a\u{D800}"` for a string with code points [U+0061, U+D800]
135 impl fmt::Debug for Wtf8Buf {
136     #[inline]
137     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
138         fmt::Debug::fmt(&**self, formatter)
139     }
140 }
141
142 impl Wtf8Buf {
143     /// Creates a new, empty WTF-8 string.
144     #[inline]
145     pub fn new() -> Wtf8Buf {
146         Wtf8Buf { bytes: Vec::new() }
147     }
148
149     /// Creates a new, empty WTF-8 string with pre-allocated capacity for `capacity` bytes.
150     #[inline]
151     pub fn with_capacity(capacity: usize) -> Wtf8Buf {
152         Wtf8Buf { bytes: Vec::with_capacity(capacity) }
153     }
154
155     /// Creates a WTF-8 string from a UTF-8 `String`.
156     ///
157     /// This takes ownership of the `String` and does not copy.
158     ///
159     /// Since WTF-8 is a superset of UTF-8, this always succeeds.
160     #[inline]
161     pub fn from_string(string: String) -> Wtf8Buf {
162         Wtf8Buf { bytes: string.into_bytes() }
163     }
164
165     /// Creates a WTF-8 string from a UTF-8 `&str` slice.
166     ///
167     /// This copies the content of the slice.
168     ///
169     /// Since WTF-8 is a superset of UTF-8, this always succeeds.
170     #[inline]
171     pub fn from_str(str: &str) -> Wtf8Buf {
172         Wtf8Buf { bytes: <[_]>::to_vec(str.as_bytes()) }
173     }
174
175     pub fn clear(&mut self) {
176         self.bytes.clear()
177     }
178
179     /// Creates a WTF-8 string from a potentially ill-formed UTF-16 slice of 16-bit code units.
180     ///
181     /// This is lossless: calling `.encode_wide()` on the resulting string
182     /// will always return the original code units.
183     pub fn from_wide(v: &[u16]) -> Wtf8Buf {
184         let mut string = Wtf8Buf::with_capacity(v.len());
185         for item in char::decode_utf16(v.iter().cloned()) {
186             match item {
187                 Ok(ch) => string.push_char(ch),
188                 Err(surrogate) => {
189                     let surrogate = surrogate.unpaired_surrogate();
190                     // Surrogates are known to be in the code point range.
191                     let code_point = unsafe { CodePoint::from_u32_unchecked(surrogate as u32) };
192                     // Skip the WTF-8 concatenation check,
193                     // surrogate pairs are already decoded by decode_utf16
194                     string.push_code_point_unchecked(code_point)
195                 }
196             }
197         }
198         string
199     }
200
201     /// Copied from String::push
202     /// This does **not** include the WTF-8 concatenation check.
203     fn push_code_point_unchecked(&mut self, code_point: CodePoint) {
204         let c = unsafe { char::from_u32_unchecked(code_point.value) };
205         let mut bytes = [0; 4];
206         let bytes = c.encode_utf8(&mut bytes).as_bytes();
207         self.bytes.extend_from_slice(bytes)
208     }
209
210     #[inline]
211     pub fn as_slice(&self) -> &Wtf8 {
212         unsafe { Wtf8::from_bytes_unchecked(&self.bytes) }
213     }
214
215     #[inline]
216     pub fn as_mut_slice(&mut self) -> &mut Wtf8 {
217         unsafe { Wtf8::from_mut_bytes_unchecked(&mut self.bytes) }
218     }
219
220     /// Reserves capacity for at least `additional` more bytes to be inserted
221     /// in the given `Wtf8Buf`.
222     /// The collection may reserve more space to avoid frequent reallocations.
223     ///
224     /// # Panics
225     ///
226     /// Panics if the new capacity overflows `usize`.
227     #[inline]
228     pub fn reserve(&mut self, additional: usize) {
229         self.bytes.reserve(additional)
230     }
231
232     #[inline]
233     pub fn reserve_exact(&mut self, additional: usize) {
234         self.bytes.reserve_exact(additional)
235     }
236
237     #[inline]
238     pub fn shrink_to_fit(&mut self) {
239         self.bytes.shrink_to_fit()
240     }
241
242     #[inline]
243     pub fn shrink_to(&mut self, min_capacity: usize) {
244         self.bytes.shrink_to(min_capacity)
245     }
246
247     /// Returns the number of bytes that this string buffer can hold without reallocating.
248     #[inline]
249     pub fn capacity(&self) -> usize {
250         self.bytes.capacity()
251     }
252
253     /// Append a UTF-8 slice at the end of the string.
254     #[inline]
255     pub fn push_str(&mut self, other: &str) {
256         self.bytes.extend_from_slice(other.as_bytes())
257     }
258
259     /// Append a WTF-8 slice at the end of the string.
260     ///
261     /// This replaces newly paired surrogates at the boundary
262     /// with a supplementary code point,
263     /// like concatenating ill-formed UTF-16 strings effectively would.
264     #[inline]
265     pub fn push_wtf8(&mut self, other: &Wtf8) {
266         match ((&*self).final_lead_surrogate(), other.initial_trail_surrogate()) {
267             // Replace newly paired surrogates by a supplementary code point.
268             (Some(lead), Some(trail)) => {
269                 let len_without_lead_surrogate = self.len() - 3;
270                 self.bytes.truncate(len_without_lead_surrogate);
271                 let other_without_trail_surrogate = &other.bytes[3..];
272                 // 4 bytes for the supplementary code point
273                 self.bytes.reserve(4 + other_without_trail_surrogate.len());
274                 self.push_char(decode_surrogate_pair(lead, trail));
275                 self.bytes.extend_from_slice(other_without_trail_surrogate);
276             }
277             _ => self.bytes.extend_from_slice(&other.bytes),
278         }
279     }
280
281     /// Append a Unicode scalar value at the end of the string.
282     #[inline]
283     pub fn push_char(&mut self, c: char) {
284         self.push_code_point_unchecked(CodePoint::from_char(c))
285     }
286
287     /// Append a code point at the end of the string.
288     ///
289     /// This replaces newly paired surrogates at the boundary
290     /// with a supplementary code point,
291     /// like concatenating ill-formed UTF-16 strings effectively would.
292     #[inline]
293     pub fn push(&mut self, code_point: CodePoint) {
294         if let trail @ 0xDC00..=0xDFFF = code_point.to_u32() {
295             if let Some(lead) = (&*self).final_lead_surrogate() {
296                 let len_without_lead_surrogate = self.len() - 3;
297                 self.bytes.truncate(len_without_lead_surrogate);
298                 self.push_char(decode_surrogate_pair(lead, trail as u16));
299                 return;
300             }
301         }
302
303         // No newly paired surrogates at the boundary.
304         self.push_code_point_unchecked(code_point)
305     }
306
307     /// Shortens a string to the specified length.
308     ///
309     /// # Panics
310     ///
311     /// Panics if `new_len` > current length,
312     /// or if `new_len` is not a code point boundary.
313     #[inline]
314     pub fn truncate(&mut self, new_len: usize) {
315         assert!(is_code_point_boundary(self, new_len));
316         self.bytes.truncate(new_len)
317     }
318
319     /// Consumes the WTF-8 string and tries to convert it to UTF-8.
320     ///
321     /// This does not copy the data.
322     ///
323     /// If the contents are not well-formed UTF-8
324     /// (that is, if the string contains surrogates),
325     /// the original WTF-8 string is returned instead.
326     pub fn into_string(self) -> Result<String, Wtf8Buf> {
327         match self.next_surrogate(0) {
328             None => Ok(unsafe { String::from_utf8_unchecked(self.bytes) }),
329             Some(_) => Err(self),
330         }
331     }
332
333     /// Consumes the WTF-8 string and converts it lossily to UTF-8.
334     ///
335     /// This does not copy the data (but may overwrite parts of it in place).
336     ///
337     /// Surrogates are replaced with `"\u{FFFD}"` (the replacement character “�”)
338     pub fn into_string_lossy(mut self) -> String {
339         let mut pos = 0;
340         loop {
341             match self.next_surrogate(pos) {
342                 Some((surrogate_pos, _)) => {
343                     pos = surrogate_pos + 3;
344                     self.bytes[surrogate_pos..pos]
345                         .copy_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes());
346                 }
347                 None => return unsafe { String::from_utf8_unchecked(self.bytes) },
348             }
349         }
350     }
351
352     /// Converts this `Wtf8Buf` into a boxed `Wtf8`.
353     #[inline]
354     pub fn into_box(self) -> Box<Wtf8> {
355         unsafe { mem::transmute(self.bytes.into_boxed_slice()) }
356     }
357
358     /// Converts a `Box<Wtf8>` into a `Wtf8Buf`.
359     pub fn from_box(boxed: Box<Wtf8>) -> Wtf8Buf {
360         let bytes: Box<[u8]> = unsafe { mem::transmute(boxed) };
361         Wtf8Buf { bytes: bytes.into_vec() }
362     }
363 }
364
365 /// Creates a new WTF-8 string from an iterator of code points.
366 ///
367 /// This replaces surrogate code point pairs with supplementary code points,
368 /// like concatenating ill-formed UTF-16 strings effectively would.
369 impl FromIterator<CodePoint> for Wtf8Buf {
370     fn from_iter<T: IntoIterator<Item = CodePoint>>(iter: T) -> Wtf8Buf {
371         let mut string = Wtf8Buf::new();
372         string.extend(iter);
373         string
374     }
375 }
376
377 /// Append code points from an iterator to the string.
378 ///
379 /// This replaces surrogate code point pairs with supplementary code points,
380 /// like concatenating ill-formed UTF-16 strings effectively would.
381 impl Extend<CodePoint> for Wtf8Buf {
382     fn extend<T: IntoIterator<Item = CodePoint>>(&mut self, iter: T) {
383         let iterator = iter.into_iter();
384         let (low, _high) = iterator.size_hint();
385         // Lower bound of one byte per code point (ASCII only)
386         self.bytes.reserve(low);
387         iterator.for_each(move |code_point| self.push(code_point));
388     }
389 }
390
391 /// A borrowed slice of well-formed WTF-8 data.
392 ///
393 /// Similar to `&str`, but can additionally contain surrogate code points
394 /// if they’re not in a surrogate pair.
395 #[derive(Eq, Ord, PartialEq, PartialOrd)]
396 pub struct Wtf8 {
397     bytes: [u8],
398 }
399
400 impl AsInner<[u8]> for Wtf8 {
401     fn as_inner(&self) -> &[u8] {
402         &self.bytes
403     }
404 }
405
406 /// Format the slice with double quotes,
407 /// and surrogates as `\u` followed by four hexadecimal digits.
408 /// Example: `"a\u{D800}"` for a slice with code points [U+0061, U+D800]
409 impl fmt::Debug for Wtf8 {
410     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
411         fn write_str_escaped(f: &mut fmt::Formatter<'_>, s: &str) -> fmt::Result {
412             use crate::fmt::Write;
413             for c in s.chars().flat_map(|c| c.escape_debug()) {
414                 f.write_char(c)?
415             }
416             Ok(())
417         }
418
419         formatter.write_str("\"")?;
420         let mut pos = 0;
421         while let Some((surrogate_pos, surrogate)) = self.next_surrogate(pos) {
422             write_str_escaped(formatter, unsafe {
423                 str::from_utf8_unchecked(&self.bytes[pos..surrogate_pos])
424             })?;
425             write!(formatter, "\\u{{{:x}}}", surrogate)?;
426             pos = surrogate_pos + 3;
427         }
428         write_str_escaped(formatter, unsafe { str::from_utf8_unchecked(&self.bytes[pos..]) })?;
429         formatter.write_str("\"")
430     }
431 }
432
433 impl fmt::Display for Wtf8 {
434     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
435         let wtf8_bytes = &self.bytes;
436         let mut pos = 0;
437         loop {
438             match self.next_surrogate(pos) {
439                 Some((surrogate_pos, _)) => {
440                     formatter.write_str(unsafe {
441                         str::from_utf8_unchecked(&wtf8_bytes[pos..surrogate_pos])
442                     })?;
443                     formatter.write_str(UTF8_REPLACEMENT_CHARACTER)?;
444                     pos = surrogate_pos + 3;
445                 }
446                 None => {
447                     let s = unsafe { str::from_utf8_unchecked(&wtf8_bytes[pos..]) };
448                     if pos == 0 { return s.fmt(formatter) } else { return formatter.write_str(s) }
449                 }
450             }
451         }
452     }
453 }
454
455 impl Wtf8 {
456     /// Creates a WTF-8 slice from a UTF-8 `&str` slice.
457     ///
458     /// Since WTF-8 is a superset of UTF-8, this always succeeds.
459     #[inline]
460     pub fn from_str(value: &str) -> &Wtf8 {
461         unsafe { Wtf8::from_bytes_unchecked(value.as_bytes()) }
462     }
463
464     /// Creates a WTF-8 slice from a WTF-8 byte slice.
465     ///
466     /// Since the byte slice is not checked for valid WTF-8, this functions is
467     /// marked unsafe.
468     #[inline]
469     unsafe fn from_bytes_unchecked(value: &[u8]) -> &Wtf8 {
470         mem::transmute(value)
471     }
472
473     /// Creates a mutable WTF-8 slice from a mutable WTF-8 byte slice.
474     ///
475     /// Since the byte slice is not checked for valid WTF-8, this functions is
476     /// marked unsafe.
477     #[inline]
478     unsafe fn from_mut_bytes_unchecked(value: &mut [u8]) -> &mut Wtf8 {
479         mem::transmute(value)
480     }
481
482     /// Returns the length, in WTF-8 bytes.
483     #[inline]
484     pub fn len(&self) -> usize {
485         self.bytes.len()
486     }
487
488     #[inline]
489     pub fn is_empty(&self) -> bool {
490         self.bytes.is_empty()
491     }
492
493     /// Returns the code point at `position` if it is in the ASCII range,
494     /// or `b'\xFF' otherwise.
495     ///
496     /// # Panics
497     ///
498     /// Panics if `position` is beyond the end of the string.
499     #[inline]
500     pub fn ascii_byte_at(&self, position: usize) -> u8 {
501         match self.bytes[position] {
502             ascii_byte @ 0x00..=0x7F => ascii_byte,
503             _ => 0xFF,
504         }
505     }
506
507     /// Returns an iterator for the string’s code points.
508     #[inline]
509     pub fn code_points(&self) -> Wtf8CodePoints<'_> {
510         Wtf8CodePoints { bytes: self.bytes.iter() }
511     }
512
513     /// Tries to convert the string to UTF-8 and return a `&str` slice.
514     ///
515     /// Returns `None` if the string contains surrogates.
516     ///
517     /// This does not copy the data.
518     #[inline]
519     pub fn as_str(&self) -> Option<&str> {
520         // Well-formed WTF-8 is also well-formed UTF-8
521         // if and only if it contains no surrogate.
522         match self.next_surrogate(0) {
523             None => Some(unsafe { str::from_utf8_unchecked(&self.bytes) }),
524             Some(_) => None,
525         }
526     }
527
528     /// Lossily converts the string to UTF-8.
529     /// Returns a UTF-8 `&str` slice if the contents are well-formed in UTF-8.
530     ///
531     /// Surrogates are replaced with `"\u{FFFD}"` (the replacement character “�”).
532     ///
533     /// This only copies the data if necessary (if it contains any surrogate).
534     pub fn to_string_lossy(&self) -> Cow<'_, str> {
535         let surrogate_pos = match self.next_surrogate(0) {
536             None => return Cow::Borrowed(unsafe { str::from_utf8_unchecked(&self.bytes) }),
537             Some((pos, _)) => pos,
538         };
539         let wtf8_bytes = &self.bytes;
540         let mut utf8_bytes = Vec::with_capacity(self.len());
541         utf8_bytes.extend_from_slice(&wtf8_bytes[..surrogate_pos]);
542         utf8_bytes.extend_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes());
543         let mut pos = surrogate_pos + 3;
544         loop {
545             match self.next_surrogate(pos) {
546                 Some((surrogate_pos, _)) => {
547                     utf8_bytes.extend_from_slice(&wtf8_bytes[pos..surrogate_pos]);
548                     utf8_bytes.extend_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes());
549                     pos = surrogate_pos + 3;
550                 }
551                 None => {
552                     utf8_bytes.extend_from_slice(&wtf8_bytes[pos..]);
553                     return Cow::Owned(unsafe { String::from_utf8_unchecked(utf8_bytes) });
554                 }
555             }
556         }
557     }
558
559     /// Converts the WTF-8 string to potentially ill-formed UTF-16
560     /// and return an iterator of 16-bit code units.
561     ///
562     /// This is lossless:
563     /// calling `Wtf8Buf::from_ill_formed_utf16` on the resulting code units
564     /// would always return the original WTF-8 string.
565     #[inline]
566     pub fn encode_wide(&self) -> EncodeWide<'_> {
567         EncodeWide { code_points: self.code_points(), extra: 0 }
568     }
569
570     #[inline]
571     fn next_surrogate(&self, mut pos: usize) -> Option<(usize, u16)> {
572         let mut iter = self.bytes[pos..].iter();
573         loop {
574             let b = *iter.next()?;
575             if b < 0x80 {
576                 pos += 1;
577             } else if b < 0xE0 {
578                 iter.next();
579                 pos += 2;
580             } else if b == 0xED {
581                 match (iter.next(), iter.next()) {
582                     (Some(&b2), Some(&b3)) if b2 >= 0xA0 => {
583                         return Some((pos, decode_surrogate(b2, b3)));
584                     }
585                     _ => pos += 3,
586                 }
587             } else if b < 0xF0 {
588                 iter.next();
589                 iter.next();
590                 pos += 3;
591             } else {
592                 iter.next();
593                 iter.next();
594                 iter.next();
595                 pos += 4;
596             }
597         }
598     }
599
600     #[inline]
601     fn final_lead_surrogate(&self) -> Option<u16> {
602         match self.bytes {
603             [.., 0xED, b2 @ 0xA0..=0xAF, b3] => Some(decode_surrogate(b2, b3)),
604             _ => None,
605         }
606     }
607
608     #[inline]
609     fn initial_trail_surrogate(&self) -> Option<u16> {
610         match self.bytes {
611             [0xED, b2 @ 0xB0..=0xBF, b3, ..] => Some(decode_surrogate(b2, b3)),
612             _ => None,
613         }
614     }
615
616     /// Boxes this `Wtf8`.
617     #[inline]
618     pub fn into_box(&self) -> Box<Wtf8> {
619         let boxed: Box<[u8]> = self.bytes.into();
620         unsafe { mem::transmute(boxed) }
621     }
622
623     /// Creates a boxed, empty `Wtf8`.
624     pub fn empty_box() -> Box<Wtf8> {
625         let boxed: Box<[u8]> = Default::default();
626         unsafe { mem::transmute(boxed) }
627     }
628
629     #[inline]
630     pub fn into_arc(&self) -> Arc<Wtf8> {
631         let arc: Arc<[u8]> = Arc::from(&self.bytes);
632         unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Wtf8) }
633     }
634
635     #[inline]
636     pub fn into_rc(&self) -> Rc<Wtf8> {
637         let rc: Rc<[u8]> = Rc::from(&self.bytes);
638         unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Wtf8) }
639     }
640 }
641
642 /// Returns a slice of the given string for the byte range [`begin`..`end`).
643 ///
644 /// # Panics
645 ///
646 /// Panics when `begin` and `end` do not point to code point boundaries,
647 /// or point beyond the end of the string.
648 impl ops::Index<ops::Range<usize>> for Wtf8 {
649     type Output = Wtf8;
650
651     #[inline]
652     fn index(&self, range: ops::Range<usize>) -> &Wtf8 {
653         // is_code_point_boundary checks that the index is in [0, .len()]
654         if range.start <= range.end
655             && is_code_point_boundary(self, range.start)
656             && is_code_point_boundary(self, range.end)
657         {
658             unsafe { slice_unchecked(self, range.start, range.end) }
659         } else {
660             slice_error_fail(self, range.start, range.end)
661         }
662     }
663 }
664
665 /// Returns a slice of the given string from byte `begin` to its end.
666 ///
667 /// # Panics
668 ///
669 /// Panics when `begin` is not at a code point boundary,
670 /// or is beyond the end of the string.
671 impl ops::Index<ops::RangeFrom<usize>> for Wtf8 {
672     type Output = Wtf8;
673
674     #[inline]
675     fn index(&self, range: ops::RangeFrom<usize>) -> &Wtf8 {
676         // is_code_point_boundary checks that the index is in [0, .len()]
677         if is_code_point_boundary(self, range.start) {
678             unsafe { slice_unchecked(self, range.start, self.len()) }
679         } else {
680             slice_error_fail(self, range.start, self.len())
681         }
682     }
683 }
684
685 /// Returns a slice of the given string from its beginning to byte `end`.
686 ///
687 /// # Panics
688 ///
689 /// Panics when `end` is not at a code point boundary,
690 /// or is beyond the end of the string.
691 impl ops::Index<ops::RangeTo<usize>> for Wtf8 {
692     type Output = Wtf8;
693
694     #[inline]
695     fn index(&self, range: ops::RangeTo<usize>) -> &Wtf8 {
696         // is_code_point_boundary checks that the index is in [0, .len()]
697         if is_code_point_boundary(self, range.end) {
698             unsafe { slice_unchecked(self, 0, range.end) }
699         } else {
700             slice_error_fail(self, 0, range.end)
701         }
702     }
703 }
704
705 impl ops::Index<ops::RangeFull> for Wtf8 {
706     type Output = Wtf8;
707
708     #[inline]
709     fn index(&self, _range: ops::RangeFull) -> &Wtf8 {
710         self
711     }
712 }
713
714 #[inline]
715 fn decode_surrogate(second_byte: u8, third_byte: u8) -> u16 {
716     // The first byte is assumed to be 0xED
717     0xD800 | (second_byte as u16 & 0x3F) << 6 | third_byte as u16 & 0x3F
718 }
719
720 #[inline]
721 fn decode_surrogate_pair(lead: u16, trail: u16) -> char {
722     let code_point = 0x10000 + ((((lead - 0xD800) as u32) << 10) | (trail - 0xDC00) as u32);
723     unsafe { char::from_u32_unchecked(code_point) }
724 }
725
726 /// Copied from core::str::StrPrelude::is_char_boundary
727 #[inline]
728 pub fn is_code_point_boundary(slice: &Wtf8, index: usize) -> bool {
729     if index == slice.len() {
730         return true;
731     }
732     match slice.bytes.get(index) {
733         None => false,
734         Some(&b) => b < 128 || b >= 192,
735     }
736 }
737
738 /// Copied from core::str::raw::slice_unchecked
739 #[inline]
740 pub unsafe fn slice_unchecked(s: &Wtf8, begin: usize, end: usize) -> &Wtf8 {
741     // memory layout of an &[u8] and &Wtf8 are the same
742     Wtf8::from_bytes_unchecked(slice::from_raw_parts(s.bytes.as_ptr().add(begin), end - begin))
743 }
744
745 /// Copied from core::str::raw::slice_error_fail
746 #[inline(never)]
747 pub fn slice_error_fail(s: &Wtf8, begin: usize, end: usize) -> ! {
748     assert!(begin <= end);
749     panic!("index {} and/or {} in `{:?}` do not lie on character boundary", begin, end, s);
750 }
751
752 /// Iterator for the code points of a WTF-8 string.
753 ///
754 /// Created with the method `.code_points()`.
755 #[derive(Clone)]
756 pub struct Wtf8CodePoints<'a> {
757     bytes: slice::Iter<'a, u8>,
758 }
759
760 impl<'a> Iterator for Wtf8CodePoints<'a> {
761     type Item = CodePoint;
762
763     #[inline]
764     fn next(&mut self) -> Option<CodePoint> {
765         next_code_point(&mut self.bytes).map(|c| CodePoint { value: c })
766     }
767
768     #[inline]
769     fn size_hint(&self) -> (usize, Option<usize>) {
770         let len = self.bytes.len();
771         (len.saturating_add(3) / 4, Some(len))
772     }
773 }
774
775 /// Generates a wide character sequence for potentially ill-formed UTF-16.
776 #[stable(feature = "rust1", since = "1.0.0")]
777 #[derive(Clone)]
778 pub struct EncodeWide<'a> {
779     code_points: Wtf8CodePoints<'a>,
780     extra: u16,
781 }
782
783 // Copied from libunicode/u_str.rs
784 #[stable(feature = "rust1", since = "1.0.0")]
785 impl<'a> Iterator for EncodeWide<'a> {
786     type Item = u16;
787
788     #[inline]
789     fn next(&mut self) -> Option<u16> {
790         if self.extra != 0 {
791             let tmp = self.extra;
792             self.extra = 0;
793             return Some(tmp);
794         }
795
796         let mut buf = [0; 2];
797         self.code_points.next().map(|code_point| {
798             let c = unsafe { char::from_u32_unchecked(code_point.value) };
799             let n = c.encode_utf16(&mut buf).len();
800             if n == 2 {
801                 self.extra = buf[1];
802             }
803             buf[0]
804         })
805     }
806
807     #[inline]
808     fn size_hint(&self) -> (usize, Option<usize>) {
809         let (low, high) = self.code_points.size_hint();
810         // every code point gets either one u16 or two u16,
811         // so this iterator is between 1 or 2 times as
812         // long as the underlying iterator.
813         (low, high.and_then(|n| n.checked_mul(2)))
814     }
815 }
816
817 impl Hash for CodePoint {
818     #[inline]
819     fn hash<H: Hasher>(&self, state: &mut H) {
820         self.value.hash(state)
821     }
822 }
823
824 impl Hash for Wtf8Buf {
825     #[inline]
826     fn hash<H: Hasher>(&self, state: &mut H) {
827         state.write(&self.bytes);
828         0xfeu8.hash(state)
829     }
830 }
831
832 impl Hash for Wtf8 {
833     #[inline]
834     fn hash<H: Hasher>(&self, state: &mut H) {
835         state.write(&self.bytes);
836         0xfeu8.hash(state)
837     }
838 }
839
840 impl Wtf8 {
841     pub fn make_ascii_uppercase(&mut self) {
842         self.bytes.make_ascii_uppercase()
843     }
844 }
845
846 #[cfg(test)]
847 mod tests {
848     use super::*;
849     use crate::borrow::Cow;
850
851     #[test]
852     fn code_point_from_u32() {
853         assert!(CodePoint::from_u32(0).is_some());
854         assert!(CodePoint::from_u32(0xD800).is_some());
855         assert!(CodePoint::from_u32(0x10FFFF).is_some());
856         assert!(CodePoint::from_u32(0x110000).is_none());
857     }
858
859     #[test]
860     fn code_point_to_u32() {
861         fn c(value: u32) -> CodePoint {
862             CodePoint::from_u32(value).unwrap()
863         }
864         assert_eq!(c(0).to_u32(), 0);
865         assert_eq!(c(0xD800).to_u32(), 0xD800);
866         assert_eq!(c(0x10FFFF).to_u32(), 0x10FFFF);
867     }
868
869     #[test]
870     fn code_point_from_char() {
871         assert_eq!(CodePoint::from_char('a').to_u32(), 0x61);
872         assert_eq!(CodePoint::from_char('💩').to_u32(), 0x1F4A9);
873     }
874
875     #[test]
876     fn code_point_to_string() {
877         assert_eq!(format!("{:?}", CodePoint::from_char('a')), "U+0061");
878         assert_eq!(format!("{:?}", CodePoint::from_char('💩')), "U+1F4A9");
879     }
880
881     #[test]
882     fn code_point_to_char() {
883         fn c(value: u32) -> CodePoint {
884             CodePoint::from_u32(value).unwrap()
885         }
886         assert_eq!(c(0x61).to_char(), Some('a'));
887         assert_eq!(c(0x1F4A9).to_char(), Some('💩'));
888         assert_eq!(c(0xD800).to_char(), None);
889     }
890
891     #[test]
892     fn code_point_to_char_lossy() {
893         fn c(value: u32) -> CodePoint {
894             CodePoint::from_u32(value).unwrap()
895         }
896         assert_eq!(c(0x61).to_char_lossy(), 'a');
897         assert_eq!(c(0x1F4A9).to_char_lossy(), '💩');
898         assert_eq!(c(0xD800).to_char_lossy(), '\u{FFFD}');
899     }
900
901     #[test]
902     fn wtf8buf_new() {
903         assert_eq!(Wtf8Buf::new().bytes, b"");
904     }
905
906     #[test]
907     fn wtf8buf_from_str() {
908         assert_eq!(Wtf8Buf::from_str("").bytes, b"");
909         assert_eq!(Wtf8Buf::from_str("aé 💩").bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
910     }
911
912     #[test]
913     fn wtf8buf_from_string() {
914         assert_eq!(Wtf8Buf::from_string(String::from("")).bytes, b"");
915         assert_eq!(
916             Wtf8Buf::from_string(String::from("aé 💩")).bytes,
917             b"a\xC3\xA9 \xF0\x9F\x92\xA9"
918         );
919     }
920
921     #[test]
922     fn wtf8buf_from_wide() {
923         assert_eq!(Wtf8Buf::from_wide(&[]).bytes, b"");
924         assert_eq!(
925             Wtf8Buf::from_wide(&[0x61, 0xE9, 0x20, 0xD83D, 0xD83D, 0xDCA9]).bytes,
926             b"a\xC3\xA9 \xED\xA0\xBD\xF0\x9F\x92\xA9"
927         );
928     }
929
930     #[test]
931     fn wtf8buf_push_str() {
932         let mut string = Wtf8Buf::new();
933         assert_eq!(string.bytes, b"");
934         string.push_str("aé 💩");
935         assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
936     }
937
938     #[test]
939     fn wtf8buf_push_char() {
940         let mut string = Wtf8Buf::from_str("aé ");
941         assert_eq!(string.bytes, b"a\xC3\xA9 ");
942         string.push_char('💩');
943         assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
944     }
945
946     #[test]
947     fn wtf8buf_push() {
948         let mut string = Wtf8Buf::from_str("aé ");
949         assert_eq!(string.bytes, b"a\xC3\xA9 ");
950         string.push(CodePoint::from_char('💩'));
951         assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
952
953         fn c(value: u32) -> CodePoint {
954             CodePoint::from_u32(value).unwrap()
955         }
956
957         let mut string = Wtf8Buf::new();
958         string.push(c(0xD83D)); // lead
959         string.push(c(0xDCA9)); // trail
960         assert_eq!(string.bytes, b"\xF0\x9F\x92\xA9"); // Magic!
961
962         let mut string = Wtf8Buf::new();
963         string.push(c(0xD83D)); // lead
964         string.push(c(0x20)); // not surrogate
965         string.push(c(0xDCA9)); // trail
966         assert_eq!(string.bytes, b"\xED\xA0\xBD \xED\xB2\xA9");
967
968         let mut string = Wtf8Buf::new();
969         string.push(c(0xD800)); // lead
970         string.push(c(0xDBFF)); // lead
971         assert_eq!(string.bytes, b"\xED\xA0\x80\xED\xAF\xBF");
972
973         let mut string = Wtf8Buf::new();
974         string.push(c(0xD800)); // lead
975         string.push(c(0xE000)); // not surrogate
976         assert_eq!(string.bytes, b"\xED\xA0\x80\xEE\x80\x80");
977
978         let mut string = Wtf8Buf::new();
979         string.push(c(0xD7FF)); // not surrogate
980         string.push(c(0xDC00)); // trail
981         assert_eq!(string.bytes, b"\xED\x9F\xBF\xED\xB0\x80");
982
983         let mut string = Wtf8Buf::new();
984         string.push(c(0x61)); // not surrogate, < 3 bytes
985         string.push(c(0xDC00)); // trail
986         assert_eq!(string.bytes, b"\x61\xED\xB0\x80");
987
988         let mut string = Wtf8Buf::new();
989         string.push(c(0xDC00)); // trail
990         assert_eq!(string.bytes, b"\xED\xB0\x80");
991     }
992
993     #[test]
994     fn wtf8buf_push_wtf8() {
995         let mut string = Wtf8Buf::from_str("aé");
996         assert_eq!(string.bytes, b"a\xC3\xA9");
997         string.push_wtf8(Wtf8::from_str(" 💩"));
998         assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
999
1000         fn w(v: &[u8]) -> &Wtf8 {
1001             unsafe { Wtf8::from_bytes_unchecked(v) }
1002         }
1003
1004         let mut string = Wtf8Buf::new();
1005         string.push_wtf8(w(b"\xED\xA0\xBD")); // lead
1006         string.push_wtf8(w(b"\xED\xB2\xA9")); // trail
1007         assert_eq!(string.bytes, b"\xF0\x9F\x92\xA9"); // Magic!
1008
1009         let mut string = Wtf8Buf::new();
1010         string.push_wtf8(w(b"\xED\xA0\xBD")); // lead
1011         string.push_wtf8(w(b" ")); // not surrogate
1012         string.push_wtf8(w(b"\xED\xB2\xA9")); // trail
1013         assert_eq!(string.bytes, b"\xED\xA0\xBD \xED\xB2\xA9");
1014
1015         let mut string = Wtf8Buf::new();
1016         string.push_wtf8(w(b"\xED\xA0\x80")); // lead
1017         string.push_wtf8(w(b"\xED\xAF\xBF")); // lead
1018         assert_eq!(string.bytes, b"\xED\xA0\x80\xED\xAF\xBF");
1019
1020         let mut string = Wtf8Buf::new();
1021         string.push_wtf8(w(b"\xED\xA0\x80")); // lead
1022         string.push_wtf8(w(b"\xEE\x80\x80")); // not surrogate
1023         assert_eq!(string.bytes, b"\xED\xA0\x80\xEE\x80\x80");
1024
1025         let mut string = Wtf8Buf::new();
1026         string.push_wtf8(w(b"\xED\x9F\xBF")); // not surrogate
1027         string.push_wtf8(w(b"\xED\xB0\x80")); // trail
1028         assert_eq!(string.bytes, b"\xED\x9F\xBF\xED\xB0\x80");
1029
1030         let mut string = Wtf8Buf::new();
1031         string.push_wtf8(w(b"a")); // not surrogate, < 3 bytes
1032         string.push_wtf8(w(b"\xED\xB0\x80")); // trail
1033         assert_eq!(string.bytes, b"\x61\xED\xB0\x80");
1034
1035         let mut string = Wtf8Buf::new();
1036         string.push_wtf8(w(b"\xED\xB0\x80")); // trail
1037         assert_eq!(string.bytes, b"\xED\xB0\x80");
1038     }
1039
1040     #[test]
1041     fn wtf8buf_truncate() {
1042         let mut string = Wtf8Buf::from_str("aé");
1043         string.truncate(1);
1044         assert_eq!(string.bytes, b"a");
1045     }
1046
1047     #[test]
1048     #[should_panic]
1049     fn wtf8buf_truncate_fail_code_point_boundary() {
1050         let mut string = Wtf8Buf::from_str("aé");
1051         string.truncate(2);
1052     }
1053
1054     #[test]
1055     #[should_panic]
1056     fn wtf8buf_truncate_fail_longer() {
1057         let mut string = Wtf8Buf::from_str("aé");
1058         string.truncate(4);
1059     }
1060
1061     #[test]
1062     fn wtf8buf_into_string() {
1063         let mut string = Wtf8Buf::from_str("aé 💩");
1064         assert_eq!(string.clone().into_string(), Ok(String::from("aé 💩")));
1065         string.push(CodePoint::from_u32(0xD800).unwrap());
1066         assert_eq!(string.clone().into_string(), Err(string));
1067     }
1068
1069     #[test]
1070     fn wtf8buf_into_string_lossy() {
1071         let mut string = Wtf8Buf::from_str("aé 💩");
1072         assert_eq!(string.clone().into_string_lossy(), String::from("aé 💩"));
1073         string.push(CodePoint::from_u32(0xD800).unwrap());
1074         assert_eq!(string.clone().into_string_lossy(), String::from("aé 💩�"));
1075     }
1076
1077     #[test]
1078     fn wtf8buf_from_iterator() {
1079         fn f(values: &[u32]) -> Wtf8Buf {
1080             values.iter().map(|&c| CodePoint::from_u32(c).unwrap()).collect::<Wtf8Buf>()
1081         }
1082         assert_eq!(f(&[0x61, 0xE9, 0x20, 0x1F4A9]).bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
1083
1084         assert_eq!(f(&[0xD83D, 0xDCA9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic!
1085         assert_eq!(f(&[0xD83D, 0x20, 0xDCA9]).bytes, b"\xED\xA0\xBD \xED\xB2\xA9");
1086         assert_eq!(f(&[0xD800, 0xDBFF]).bytes, b"\xED\xA0\x80\xED\xAF\xBF");
1087         assert_eq!(f(&[0xD800, 0xE000]).bytes, b"\xED\xA0\x80\xEE\x80\x80");
1088         assert_eq!(f(&[0xD7FF, 0xDC00]).bytes, b"\xED\x9F\xBF\xED\xB0\x80");
1089         assert_eq!(f(&[0x61, 0xDC00]).bytes, b"\x61\xED\xB0\x80");
1090         assert_eq!(f(&[0xDC00]).bytes, b"\xED\xB0\x80");
1091     }
1092
1093     #[test]
1094     fn wtf8buf_extend() {
1095         fn e(initial: &[u32], extended: &[u32]) -> Wtf8Buf {
1096             fn c(value: &u32) -> CodePoint {
1097                 CodePoint::from_u32(*value).unwrap()
1098             }
1099             let mut string = initial.iter().map(c).collect::<Wtf8Buf>();
1100             string.extend(extended.iter().map(c));
1101             string
1102         }
1103
1104         assert_eq!(e(&[0x61, 0xE9], &[0x20, 0x1F4A9]).bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
1105
1106         assert_eq!(e(&[0xD83D], &[0xDCA9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic!
1107         assert_eq!(e(&[0xD83D, 0x20], &[0xDCA9]).bytes, b"\xED\xA0\xBD \xED\xB2\xA9");
1108         assert_eq!(e(&[0xD800], &[0xDBFF]).bytes, b"\xED\xA0\x80\xED\xAF\xBF");
1109         assert_eq!(e(&[0xD800], &[0xE000]).bytes, b"\xED\xA0\x80\xEE\x80\x80");
1110         assert_eq!(e(&[0xD7FF], &[0xDC00]).bytes, b"\xED\x9F\xBF\xED\xB0\x80");
1111         assert_eq!(e(&[0x61], &[0xDC00]).bytes, b"\x61\xED\xB0\x80");
1112         assert_eq!(e(&[], &[0xDC00]).bytes, b"\xED\xB0\x80");
1113     }
1114
1115     #[test]
1116     fn wtf8buf_show() {
1117         let mut string = Wtf8Buf::from_str("a\té \u{7f}💩\r");
1118         string.push(CodePoint::from_u32(0xD800).unwrap());
1119         assert_eq!(format!("{:?}", string), "\"a\\té \\u{7f}\u{1f4a9}\\r\\u{d800}\"");
1120     }
1121
1122     #[test]
1123     fn wtf8buf_as_slice() {
1124         assert_eq!(Wtf8Buf::from_str("aé").as_slice(), Wtf8::from_str("aé"));
1125     }
1126
1127     #[test]
1128     fn wtf8buf_show_str() {
1129         let text = "a\té 💩\r";
1130         let string = Wtf8Buf::from_str(text);
1131         assert_eq!(format!("{:?}", text), format!("{:?}", string));
1132     }
1133
1134     #[test]
1135     fn wtf8_from_str() {
1136         assert_eq!(&Wtf8::from_str("").bytes, b"");
1137         assert_eq!(&Wtf8::from_str("aé 💩").bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
1138     }
1139
1140     #[test]
1141     fn wtf8_len() {
1142         assert_eq!(Wtf8::from_str("").len(), 0);
1143         assert_eq!(Wtf8::from_str("aé 💩").len(), 8);
1144     }
1145
1146     #[test]
1147     fn wtf8_slice() {
1148         assert_eq!(&Wtf8::from_str("aé 💩")[1..4].bytes, b"\xC3\xA9 ");
1149     }
1150
1151     #[test]
1152     #[should_panic]
1153     fn wtf8_slice_not_code_point_boundary() {
1154         &Wtf8::from_str("aé 💩")[2..4];
1155     }
1156
1157     #[test]
1158     fn wtf8_slice_from() {
1159         assert_eq!(&Wtf8::from_str("aé 💩")[1..].bytes, b"\xC3\xA9 \xF0\x9F\x92\xA9");
1160     }
1161
1162     #[test]
1163     #[should_panic]
1164     fn wtf8_slice_from_not_code_point_boundary() {
1165         &Wtf8::from_str("aé 💩")[2..];
1166     }
1167
1168     #[test]
1169     fn wtf8_slice_to() {
1170         assert_eq!(&Wtf8::from_str("aé 💩")[..4].bytes, b"a\xC3\xA9 ");
1171     }
1172
1173     #[test]
1174     #[should_panic]
1175     fn wtf8_slice_to_not_code_point_boundary() {
1176         &Wtf8::from_str("aé 💩")[5..];
1177     }
1178
1179     #[test]
1180     fn wtf8_ascii_byte_at() {
1181         let slice = Wtf8::from_str("aé 💩");
1182         assert_eq!(slice.ascii_byte_at(0), b'a');
1183         assert_eq!(slice.ascii_byte_at(1), b'\xFF');
1184         assert_eq!(slice.ascii_byte_at(2), b'\xFF');
1185         assert_eq!(slice.ascii_byte_at(3), b' ');
1186         assert_eq!(slice.ascii_byte_at(4), b'\xFF');
1187     }
1188
1189     #[test]
1190     fn wtf8_code_points() {
1191         fn c(value: u32) -> CodePoint {
1192             CodePoint::from_u32(value).unwrap()
1193         }
1194         fn cp(string: &Wtf8Buf) -> Vec<Option<char>> {
1195             string.code_points().map(|c| c.to_char()).collect::<Vec<_>>()
1196         }
1197         let mut string = Wtf8Buf::from_str("é ");
1198         assert_eq!(cp(&string), [Some('é'), Some(' ')]);
1199         string.push(c(0xD83D));
1200         assert_eq!(cp(&string), [Some('é'), Some(' '), None]);
1201         string.push(c(0xDCA9));
1202         assert_eq!(cp(&string), [Some('é'), Some(' '), Some('💩')]);
1203     }
1204
1205     #[test]
1206     fn wtf8_as_str() {
1207         assert_eq!(Wtf8::from_str("").as_str(), Some(""));
1208         assert_eq!(Wtf8::from_str("aé 💩").as_str(), Some("aé 💩"));
1209         let mut string = Wtf8Buf::new();
1210         string.push(CodePoint::from_u32(0xD800).unwrap());
1211         assert_eq!(string.as_str(), None);
1212     }
1213
1214     #[test]
1215     fn wtf8_to_string_lossy() {
1216         assert_eq!(Wtf8::from_str("").to_string_lossy(), Cow::Borrowed(""));
1217         assert_eq!(Wtf8::from_str("aé 💩").to_string_lossy(), Cow::Borrowed("aé 💩"));
1218         let mut string = Wtf8Buf::from_str("aé 💩");
1219         string.push(CodePoint::from_u32(0xD800).unwrap());
1220         let expected: Cow<'_, str> = Cow::Owned(String::from("aé 💩�"));
1221         assert_eq!(string.to_string_lossy(), expected);
1222     }
1223
1224     #[test]
1225     fn wtf8_display() {
1226         fn d(b: &[u8]) -> String {
1227             (&unsafe { Wtf8::from_bytes_unchecked(b) }).to_string()
1228         }
1229
1230         assert_eq!("", d("".as_bytes()));
1231         assert_eq!("aé 💩", d("aé 💩".as_bytes()));
1232
1233         let mut string = Wtf8Buf::from_str("aé 💩");
1234         string.push(CodePoint::from_u32(0xD800).unwrap());
1235         assert_eq!("aé 💩�", d(string.as_inner()));
1236     }
1237
1238     #[test]
1239     fn wtf8_encode_wide() {
1240         let mut string = Wtf8Buf::from_str("aé ");
1241         string.push(CodePoint::from_u32(0xD83D).unwrap());
1242         string.push_char('💩');
1243         assert_eq!(
1244             string.encode_wide().collect::<Vec<_>>(),
1245             vec![0x61, 0xE9, 0x20, 0xD83D, 0xD83D, 0xDCA9]
1246         );
1247     }
1248 }