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