Skip to main content

alloc/wtf8/
mod.rs

1//! Heap-allocated counterpart to core `wtf8` module.
2#![unstable(
3    feature = "wtf8_internals",
4    issue = "none",
5    reason = "this is internal code for representing OsStr on some platforms and not a public API"
6)]
7// rustdoc bug: doc(hidden) on the module won't stop types in the module from showing up in trait
8// implementations, so, we'll have to add more doc(hidden)s anyway
9#![doc(hidden)]
10
11// Note: This module is also included in the alloctests crate using #[path] to
12// run the tests. See the comment there for an explanation why this is the case.
13
14#[cfg(test)]
15mod tests;
16
17use core::char::encode_utf8_raw;
18use core::hash::{Hash, Hasher};
19pub use core::wtf8::{CodePoint, Wtf8};
20#[cfg(not(test))]
21pub use core::wtf8::{EncodeWide, Wtf8CodePoints};
22use core::{fmt, mem, ops, str};
23
24use crate::borrow::{Cow, ToOwned};
25use crate::boxed::Box;
26use crate::collections::TryReserveError;
27#[cfg(not(test))]
28use crate::rc::Rc;
29use crate::string::String;
30#[cfg(all(not(test), target_has_atomic = "ptr"))]
31use crate::sync::Arc;
32use crate::vec::Vec;
33
34/// An owned, growable string of [well-formed WTF-8](https://wtf-8.codeberg.page/#well-formed) data.
35///
36/// Similar to `String`, but can additionally contain surrogate code points
37/// if they’re not in a surrogate pair.
38#[derive(#[automatically_derived]
impl ::core::cmp::Eq for Wtf8Buf {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<Vec<u8>>;
        let _: ::core::cmp::AssertParamIsEq<bool>;
    }
}Eq, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for Wtf8Buf { }
#[automatically_derived]
impl ::core::cmp::PartialEq for Wtf8Buf {
    #[inline]
    fn eq(&self, other: &Wtf8Buf) -> bool {
        self.is_known_utf8 == other.is_known_utf8 && self.bytes == other.bytes
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Ord for Wtf8Buf {
    #[inline]
    fn cmp(&self, other: &Wtf8Buf) -> ::core::cmp::Ordering {
        match ::core::cmp::Ord::cmp(&self.bytes, &other.bytes) {
            ::core::cmp::Ordering::Equal =>
                ::core::cmp::Ord::cmp(&self.is_known_utf8,
                    &other.is_known_utf8),
            cmp => cmp,
        }
    }
}Ord, #[automatically_derived]
impl ::core::cmp::PartialOrd for Wtf8Buf {
    #[inline]
    fn partial_cmp(&self, other: &Wtf8Buf)
        -> ::core::option::Option<::core::cmp::Ordering> {
        ::core::option::Option::Some(::core::cmp::Ord::cmp(self, other))
    }
}PartialOrd, #[automatically_derived]
impl ::core::clone::Clone for Wtf8Buf {
    #[inline]
    fn clone(&self) -> Wtf8Buf {
        Wtf8Buf {
            bytes: ::core::clone::Clone::clone(&self.bytes),
            is_known_utf8: ::core::clone::Clone::clone(&self.is_known_utf8),
        }
    }
}Clone)]
39#[doc(hidden)]
40pub struct Wtf8Buf {
41    bytes: Vec<u8>,
42
43    /// Do we know that `bytes` holds a valid UTF-8 encoding? We can easily
44    /// know this if we're constructed from a `String` or `&str`.
45    ///
46    /// It is possible for `bytes` to have valid UTF-8 without this being
47    /// set, such as when we're concatenating `&Wtf8`'s and surrogates become
48    /// paired, as we don't bother to rescan the entire string.
49    is_known_utf8: bool,
50}
51
52impl ops::Deref for Wtf8Buf {
53    type Target = Wtf8;
54
55    fn deref(&self) -> &Wtf8 {
56        self.as_slice()
57    }
58}
59
60impl ops::DerefMut for Wtf8Buf {
61    fn deref_mut(&mut self) -> &mut Wtf8 {
62        self.as_mut_slice()
63    }
64}
65
66/// Formats the string in double quotes, with characters escaped according to
67/// [`char::escape_debug`] and unpaired surrogates represented as `\u{xxxx}`,
68/// where each `x` is a hexadecimal digit.
69///
70/// For example, the code units [U+0061, U+D800, U+000A] are formatted as
71/// `"a\u{D800}\n"`.
72impl fmt::Debug for Wtf8Buf {
73    #[inline]
74    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
75        fmt::Debug::fmt(&**self, formatter)
76    }
77}
78
79/// Formats the string with unpaired surrogates substituted with the replacement
80/// character, U+FFFD.
81impl fmt::Display for Wtf8Buf {
82    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
83        if let Some(s) = self.as_known_utf8() {
84            fmt::Display::fmt(s, formatter)
85        } else {
86            fmt::Display::fmt(&**self, formatter)
87        }
88    }
89}
90
91#[cfg_attr(test, allow(dead_code))]
92impl Wtf8Buf {
93    /// Creates a new, empty WTF-8 string.
94    #[inline]
95    pub fn new() -> Wtf8Buf {
96        Wtf8Buf { bytes: Vec::new(), is_known_utf8: true }
97    }
98
99    /// Creates a new, empty WTF-8 string with pre-allocated capacity for `capacity` bytes.
100    #[inline]
101    pub fn with_capacity(capacity: usize) -> Wtf8Buf {
102        Wtf8Buf { bytes: Vec::with_capacity(capacity), is_known_utf8: true }
103    }
104
105    /// Creates a WTF-8 string from a WTF-8 byte vec.
106    ///
107    /// # Safety
108    ///
109    /// `value` must contain [well-formed WTF-8](https://wtf-8.codeberg.page/#well-formed).
110    #[inline]
111    pub unsafe fn from_bytes_unchecked(value: Vec<u8>) -> Wtf8Buf {
112        Wtf8Buf { bytes: value, is_known_utf8: false }
113    }
114
115    /// Creates a WTF-8 string from a UTF-8 `String`.
116    ///
117    /// This takes ownership of the `String` and does not copy.
118    ///
119    /// Since WTF-8 is a superset of UTF-8, this always succeeds.
120    #[inline]
121    pub const fn from_string(string: String) -> Wtf8Buf {
122        Wtf8Buf { bytes: string.into_bytes(), is_known_utf8: true }
123    }
124
125    /// Creates a WTF-8 string from a UTF-8 `&str` slice.
126    ///
127    /// This copies the content of the slice.
128    ///
129    /// Since WTF-8 is a superset of UTF-8, this always succeeds.
130    #[inline]
131    pub fn from_str(s: &str) -> Wtf8Buf {
132        Wtf8Buf { bytes: s.as_bytes().to_vec(), is_known_utf8: true }
133    }
134
135    pub fn clear(&mut self) {
136        self.bytes.clear();
137        self.is_known_utf8 = true;
138    }
139
140    /// Creates a WTF-8 string from a potentially ill-formed UTF-16 slice of 16-bit code units.
141    ///
142    /// This is lossless: calling `.encode_wide()` on the resulting string
143    /// will always return the original code units.
144    pub fn from_wide(v: &[u16]) -> Wtf8Buf {
145        let mut string = Wtf8Buf::with_capacity(v.len());
146        for item in char::decode_utf16(v.iter().cloned()) {
147            match item {
148                Ok(ch) => string.push_char(ch),
149                Err(surrogate) => {
150                    let surrogate = surrogate.unpaired_surrogate();
151                    // SAFETY: Surrogates are known to be in the code point range.
152                    let code_point = unsafe { CodePoint::from_u32_unchecked(surrogate as u32) };
153                    // The string will now contain an unpaired surrogate.
154                    string.is_known_utf8 = false;
155                    // SAFETY: `decode_utf16` reports only unpaired surrogates here,
156                    // so this code point cannot form a surrogate pair with the
157                    // preceding and succeeding contents. The existing buffer is
158                    // well-formed WTF-8, and appending this encoded surrogate
159                    // preserves that invariant.
160                    unsafe {
161                        string.push_code_point_unchecked(code_point);
162                    }
163                }
164            }
165        }
166        string
167    }
168
169    /// Appends the given `char` to the end of this string.
170    /// This does **not** include the WTF-8 concatenation check or `is_known_utf8` check.
171    /// Copied from String::push.
172    ///
173    /// # Safety
174    ///
175    /// `self` must contain [well-formed WTF-8](https://wtf-8.codeberg.page/#well-formed),
176    /// and appending `code_point` must preserve that invariant. In particular,
177    /// `code_point` must not be a trailing surrogate if `self` ends with a leading surrogate.
178    ///
179    /// If `self.is_known_utf8` is true, `code_point` must not be a surrogate.
180    unsafe fn push_code_point_unchecked(&mut self, code_point: CodePoint) {
181        let mut bytes = [0; char::MAX_LEN_UTF8];
182        let bytes = encode_utf8_raw(code_point.to_u32(), &mut bytes);
183        self.bytes.extend_from_slice(bytes)
184    }
185
186    #[inline]
187    pub fn as_slice(&self) -> &Wtf8 {
188        // SAFETY: `self` maintains `bytes` as well-formed WTF-8.
189        unsafe { Wtf8::from_bytes_unchecked(&self.bytes) }
190    }
191
192    #[inline]
193    pub fn as_mut_slice(&mut self) -> &mut Wtf8 {
194        // SAFETY: `self` maintains `bytes` as well-formed WTF-8.
195        unsafe { Wtf8::from_mut_bytes_unchecked(&mut self.bytes) }
196    }
197
198    /// Converts the string to UTF-8 without validation, if it was created from
199    /// valid UTF-8.
200    #[inline]
201    fn as_known_utf8(&self) -> Option<&str> {
202        if self.is_known_utf8 {
203            // SAFETY: The buffer is known to be valid UTF-8.
204            Some(unsafe { str::from_utf8_unchecked(self.as_bytes()) })
205        } else {
206            None
207        }
208    }
209
210    /// Reserves capacity for at least `additional` more bytes to be inserted
211    /// in the given `Wtf8Buf`.
212    /// The collection may reserve more space to avoid frequent reallocations.
213    ///
214    /// # Panics
215    ///
216    /// Panics if the new capacity exceeds `isize::MAX` bytes.
217    #[inline]
218    pub fn reserve(&mut self, additional: usize) {
219        self.bytes.reserve(additional)
220    }
221
222    /// Tries to reserve capacity for at least `additional` more bytes to be
223    /// inserted in the given `Wtf8Buf`. The `Wtf8Buf` may reserve more space to
224    /// avoid frequent reallocations. After calling `try_reserve`, capacity will
225    /// be greater than or equal to `self.len() + additional`. Does nothing if
226    /// capacity is already sufficient. This method preserves the contents even
227    /// if an error occurs.
228    ///
229    /// # Errors
230    ///
231    /// If the capacity overflows, or the allocator reports a failure, then an error
232    /// is returned.
233    #[inline]
234    pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
235        self.bytes.try_reserve(additional)
236    }
237
238    #[inline]
239    pub fn reserve_exact(&mut self, additional: usize) {
240        self.bytes.reserve_exact(additional)
241    }
242
243    /// Tries to reserve the minimum capacity for exactly `additional` more
244    /// bytes to be inserted in the given `Wtf8Buf`. After calling
245    /// `try_reserve_exact`, capacity will be greater than or equal to
246    /// `self.len() + additional` if it returns `Ok(())`.
247    /// Does nothing if the capacity is already sufficient.
248    ///
249    /// Note that the allocator may give the `Wtf8Buf` more space than it
250    /// requests. Therefore, capacity can not be relied upon to be precisely
251    /// minimal. Prefer [`try_reserve`] if future insertions are expected.
252    ///
253    /// [`try_reserve`]: Wtf8Buf::try_reserve
254    ///
255    /// # Errors
256    ///
257    /// If the capacity overflows, or the allocator reports a failure, then an error
258    /// is returned.
259    #[inline]
260    pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
261        self.bytes.try_reserve_exact(additional)
262    }
263
264    #[inline]
265    pub fn shrink_to_fit(&mut self) {
266        self.bytes.shrink_to_fit()
267    }
268
269    #[inline]
270    pub fn shrink_to(&mut self, min_capacity: usize) {
271        self.bytes.shrink_to(min_capacity)
272    }
273
274    #[inline]
275    pub fn leak<'a>(self) -> &'a mut Wtf8 {
276        // SAFETY: `self` maintains `bytes` as well-formed WTF-8.
277        unsafe { Wtf8::from_mut_bytes_unchecked(self.bytes.leak()) }
278    }
279
280    /// Returns the number of bytes that this string buffer can hold without reallocating.
281    #[inline]
282    pub fn capacity(&self) -> usize {
283        self.bytes.capacity()
284    }
285
286    /// Append a UTF-8 slice at the end of the string.
287    #[inline]
288    pub fn push_str(&mut self, other: &str) {
289        self.bytes.extend_from_slice(other.as_bytes())
290    }
291
292    /// Append a WTF-8 slice at the end of the string.
293    ///
294    /// This replaces newly paired surrogates at the boundary
295    /// with a supplementary code point,
296    /// like concatenating ill-formed UTF-16 strings effectively would.
297    #[inline]
298    pub fn push_wtf8(&mut self, other: &Wtf8) {
299        match ((*self).final_lead_surrogate(), other.initial_trail_surrogate()) {
300            // Replace newly paired surrogates by a supplementary code point.
301            (Some(lead), Some(trail)) => {
302                let len_without_lead_surrogate = self.len() - 3;
303                self.bytes.truncate(len_without_lead_surrogate);
304                let other_without_trail_surrogate = &other.as_bytes()[3..];
305                // 4 bytes for the supplementary code point
306                self.bytes.reserve(4 + other_without_trail_surrogate.len());
307                self.push_char(decode_surrogate_pair(lead, trail));
308                self.bytes.extend_from_slice(other_without_trail_surrogate);
309            }
310            _ => {
311                // If we'll be pushing a string containing a surrogate, we may
312                // no longer have UTF-8.
313                if self.is_known_utf8 && other.next_surrogate(0).is_some() {
314                    self.is_known_utf8 = false;
315                }
316
317                self.bytes.extend_from_slice(other.as_bytes());
318            }
319        }
320    }
321
322    /// Append a Unicode scalar value at the end of the string.
323    #[inline]
324    pub fn push_char(&mut self, c: char) {
325        // SAFETY: It's always safe to push a char.
326        unsafe { self.push_code_point_unchecked(CodePoint::from_char(c)) }
327    }
328
329    /// Append a code point at the end of the string.
330    ///
331    /// This replaces newly paired surrogates at the boundary
332    /// with a supplementary code point,
333    /// like concatenating ill-formed UTF-16 strings effectively would.
334    #[inline]
335    pub fn push(&mut self, code_point: CodePoint) {
336        if let Some(trail) = code_point.to_trail_surrogate() {
337            if let Some(lead) = (*self).final_lead_surrogate() {
338                let len_without_lead_surrogate = self.len() - 3;
339                self.bytes.truncate(len_without_lead_surrogate);
340                self.push_char(decode_surrogate_pair(lead, trail));
341                return;
342            }
343
344            // We're pushing a trailing surrogate.
345            self.is_known_utf8 = false;
346        } else if code_point.to_lead_surrogate().is_some() {
347            // We're pushing a leading surrogate.
348            self.is_known_utf8 = false;
349        }
350
351        // SAFETY: We have checked that no newly paired surrogates at the boundary.
352        unsafe { self.push_code_point_unchecked(code_point) }
353    }
354
355    /// Shortens a string to the specified length.
356    ///
357    /// If `new_len` is greater than the string's current length, this has no
358    /// effect.
359    ///
360    /// # Panics
361    ///
362    /// Panics if `new_len` does not lie on a code point boundary.
363    #[inline]
364    pub fn truncate(&mut self, new_len: usize) {
365        if new_len <= self.len() {
366            if !self.is_code_point_boundary(new_len) {
    ::core::panicking::panic("assertion failed: self.is_code_point_boundary(new_len)")
};assert!(self.is_code_point_boundary(new_len));
367            self.bytes.truncate(new_len)
368        }
369    }
370
371    /// Consumes the WTF-8 string and tries to convert it to a vec of bytes.
372    #[inline]
373    pub fn into_bytes(self) -> Vec<u8> {
374        self.bytes
375    }
376
377    /// Consumes the WTF-8 string and tries to convert it to UTF-8.
378    ///
379    /// This does not copy the data.
380    ///
381    /// If the contents are not well-formed UTF-8
382    /// (that is, if the string contains surrogates),
383    /// the original WTF-8 string is returned instead.
384    pub fn into_string(self) -> Result<String, Wtf8Buf> {
385        if self.is_known_utf8 || self.next_surrogate(0).is_none() {
386            // SAFETY: We have checked that `self.bytes` contains valid UTF-8.
387            Ok(unsafe { String::from_utf8_unchecked(self.bytes) })
388        } else {
389            Err(self)
390        }
391    }
392
393    /// Consumes the WTF-8 string and converts it lossily to UTF-8.
394    ///
395    /// This does not copy the data (but may overwrite parts of it in place).
396    ///
397    /// Surrogates are replaced with `"\u{FFFD}"` (the replacement character “�”)
398    pub fn into_string_lossy(mut self) -> String {
399        if !self.is_known_utf8 {
400            let mut pos = 0;
401            while let Some((surrogate_pos, _)) = self.next_surrogate(pos) {
402                pos = surrogate_pos + 3;
403                // Surrogates and the replacement character are all 3 bytes, so
404                // they can substituted in-place.
405                self.bytes[surrogate_pos..pos].copy_from_slice("\u{FFFD}".as_bytes());
406            }
407        }
408        // SAFETY: Now `self.bytes` contains valid UTF-8.
409        unsafe { String::from_utf8_unchecked(self.bytes) }
410    }
411
412    /// Converts this `Wtf8Buf` into a boxed `Wtf8`.
413    #[inline]
414    pub fn into_box(self) -> Box<Wtf8> {
415        // SAFETY: `Wtf8` is a transparent wrapper around `[u8]`, and
416        // `self.bytes.into_boxed_slice()` returns a `Box<[u8]>`.
417        // Therefore, transmuting `Box<[u8]>` to `Box<Wtf8>` is safe.
418        unsafe { mem::transmute(self.bytes.into_boxed_slice()) }
419    }
420
421    /// Converts a `Box<Wtf8>` into a `Wtf8Buf`.
422    pub fn from_box(boxed: Box<Wtf8>) -> Wtf8Buf {
423        // SAFETY: `Wtf8` is a transparent wrapper around `[u8]`, and `boxed` is
424        // a `Box<Wtf8>`. Therefore, transmuting `Box<Wtf8>` to `Box<[u8]>` is safe.
425        let bytes: Box<[u8]> = unsafe { mem::transmute(boxed) };
426        Wtf8Buf { bytes: bytes.into_vec(), is_known_utf8: false }
427    }
428
429    /// Provides plumbing to core `Vec::extend_from_slice`.
430    /// More well behaving alternative to allowing outer types
431    /// full mutable access to the core `Vec`.
432    ///
433    /// # Safety
434    ///
435    /// `self` and `other` must contain [well-formed WTF-8](https://wtf-8.codeberg.page/#well-formed),
436    /// and appending `other` to `self` must preserve that invariant.
437    /// In particular, `self` must not end with a leading surrogate,
438    /// or `other` must not start with a trailing surrogate.
439    #[inline]
440    pub unsafe fn extend_from_slice_unchecked(&mut self, other: &[u8]) {
441        self.bytes.extend_from_slice(other);
442        self.is_known_utf8 = false;
443    }
444}
445
446/// Creates a new WTF-8 string from an iterator of code points.
447///
448/// This replaces surrogate code point pairs with supplementary code points,
449/// like concatenating ill-formed UTF-16 strings effectively would.
450impl FromIterator<CodePoint> for Wtf8Buf {
451    fn from_iter<T: IntoIterator<Item = CodePoint>>(iter: T) -> Wtf8Buf {
452        let mut string = Wtf8Buf::new();
453        string.extend(iter);
454        string
455    }
456}
457
458/// Append code points from an iterator to the string.
459///
460/// This replaces surrogate code point pairs with supplementary code points,
461/// like concatenating ill-formed UTF-16 strings effectively would.
462impl Extend<CodePoint> for Wtf8Buf {
463    fn extend<T: IntoIterator<Item = CodePoint>>(&mut self, iter: T) {
464        let iterator = iter.into_iter();
465        let (low, _high) = iterator.size_hint();
466        // Lower bound of one byte per code point (ASCII only)
467        self.bytes.reserve(low);
468        iterator.for_each(move |code_point| self.push(code_point));
469    }
470
471    #[inline]
472    fn extend_one(&mut self, code_point: CodePoint) {
473        self.push(code_point);
474    }
475
476    #[inline]
477    fn extend_reserve(&mut self, additional: usize) {
478        // Lower bound of one byte per code point (ASCII only)
479        self.bytes.reserve(additional);
480    }
481}
482
483/// Creates an owned `Wtf8Buf` from a borrowed `Wtf8`.
484pub(super) fn to_owned(slice: &Wtf8) -> Wtf8Buf {
485    Wtf8Buf { bytes: slice.as_bytes().to_vec(), is_known_utf8: false }
486}
487
488/// Lossily converts the string to UTF-8.
489/// Returns a UTF-8 `&str` slice if the contents are well-formed in UTF-8.
490///
491/// Surrogates are replaced with `"\u{FFFD}"` (the replacement character “�”).
492///
493/// This only copies the data if necessary (if it contains any surrogate).
494pub(super) fn to_string_lossy(slice: &Wtf8) -> Cow<'_, str> {
495    let Some((surrogate_pos, _)) = slice.next_surrogate(0) else {
496        // SAFETY: `next_surrogate` found no surrogate, so the well-formed WTF-8
497        // bytes are valid UTF-8.
498        return Cow::Borrowed(unsafe { str::from_utf8_unchecked(slice.as_bytes()) });
499    };
500    let wtf8_bytes = slice.as_bytes();
501    let mut utf8_bytes = Vec::with_capacity(slice.len());
502    utf8_bytes.extend_from_slice(&wtf8_bytes[..surrogate_pos]);
503    utf8_bytes.extend_from_slice("\u{FFFD}".as_bytes());
504    let mut pos = surrogate_pos + 3;
505    loop {
506        match slice.next_surrogate(pos) {
507            Some((surrogate_pos, _)) => {
508                utf8_bytes.extend_from_slice(&wtf8_bytes[pos..surrogate_pos]);
509                utf8_bytes.extend_from_slice("\u{FFFD}".as_bytes());
510                pos = surrogate_pos + 3;
511            }
512            None => {
513                utf8_bytes.extend_from_slice(&wtf8_bytes[pos..]);
514                // SAFETY: Every surrogate was replaced with `"\u{FFFD}"`,
515                // and the remaining bytes are valid UTF-8, so `utf8_bytes` is valid UTF-8.
516                return Cow::Owned(unsafe { String::from_utf8_unchecked(utf8_bytes) });
517            }
518        }
519    }
520}
521
522#[inline]
523pub(super) fn clone_into(slice: &Wtf8, buf: &mut Wtf8Buf) {
524    buf.is_known_utf8 = false;
525    slice.as_bytes().clone_into(&mut buf.bytes);
526}
527
528#[cfg(not(test))]
529impl Wtf8 {
530    #[rustc_allow_incoherent_impl]
531    pub fn to_owned(&self) -> Wtf8Buf {
532        to_owned(self)
533    }
534
535    #[rustc_allow_incoherent_impl]
536    pub fn clone_into(&self, buf: &mut Wtf8Buf) {
537        clone_into(self, buf)
538    }
539
540    #[rustc_allow_incoherent_impl]
541    pub fn to_string_lossy(&self) -> Cow<'_, str> {
542        to_string_lossy(self)
543    }
544
545    #[rustc_allow_incoherent_impl]
546    pub fn into_box(&self) -> Box<Wtf8> {
547        let boxed: Box<[u8]> = self.as_bytes().into();
548        // SAFETY: `Wtf8` is a transparent wrapper around `[u8]`, and `boxed` is
549        // a `Box<[u8]>`. Therefore, transmuting `Box<[u8]>` to `Box<Wtf8>` is safe.
550        unsafe { mem::transmute(boxed) }
551    }
552
553    #[rustc_allow_incoherent_impl]
554    pub fn empty_box() -> Box<Wtf8> {
555        let boxed: Box<[u8]> = Default::default();
556        // SAFETY: `Wtf8` is a transparent wrapper around `[u8]`, and `boxed` is
557        // an empty `Box<[u8]>`. Therefore, transmuting it to `Box<Wtf8>` is safe.
558        unsafe { mem::transmute(boxed) }
559    }
560
561    #[cfg(target_has_atomic = "ptr")]
562    #[rustc_allow_incoherent_impl]
563    pub fn into_arc(&self) -> Arc<Wtf8> {
564        let arc: Arc<[u8]> = Arc::from(self.as_bytes());
565        // SAFETY: `Wtf8` is a transparent wrapper around `[u8]`.
566        unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Wtf8) }
567    }
568
569    #[rustc_allow_incoherent_impl]
570    pub fn into_rc(&self) -> Rc<Wtf8> {
571        let rc: Rc<[u8]> = Rc::from(self.as_bytes());
572        // SAFETY: `Wtf8` is a transparent wrapper around `[u8]`.
573        unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Wtf8) }
574    }
575
576    #[inline]
577    #[rustc_allow_incoherent_impl]
578    pub fn to_ascii_lowercase(&self) -> Wtf8Buf {
579        Wtf8Buf { bytes: self.as_bytes().to_ascii_lowercase(), is_known_utf8: false }
580    }
581
582    #[inline]
583    #[rustc_allow_incoherent_impl]
584    pub fn to_ascii_uppercase(&self) -> Wtf8Buf {
585        Wtf8Buf { bytes: self.as_bytes().to_ascii_uppercase(), is_known_utf8: false }
586    }
587}
588
589#[inline]
590fn decode_surrogate_pair(lead: u16, trail: u16) -> char {
591    let code_point = 0x10000 + ((((lead - 0xD800) as u32) << 10) | (trail - 0xDC00) as u32);
592    // SAFETY: The computed `code_point` is in 0x10000..=0x10FFFF and is not a surrogate.
593    unsafe { char::from_u32_unchecked(code_point) }
594}
595
596impl Hash for Wtf8Buf {
597    #[inline]
598    fn hash<H: Hasher>(&self, state: &mut H) {
599        state.write(&self.bytes);
600        0xfeu8.hash(state)
601    }
602}