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