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)]
1011// 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.
1314#[cfg(test)]
15mod tests;
1617use 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};
2324use 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;
3334/// 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>,
4243/// 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.
49is_known_utf8: bool,
50}
5152impl ops::Dereffor Wtf8Buf {
53type Target = Wtf8;
5455fn deref(&self) -> &Wtf8 {
56self.as_slice()
57 }
58}
5960impl ops::DerefMutfor Wtf8Buf {
61fn deref_mut(&mut self) -> &mut Wtf8 {
62self.as_mut_slice()
63 }
64}
6566/// 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::Debugfor Wtf8Buf {
73#[inline]
74fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
75 fmt::Debug::fmt(&**self, formatter)
76 }
77}
7879/// Formats the string with unpaired surrogates substituted with the replacement
80/// character, U+FFFD.
81impl fmt::Displayfor Wtf8Buf {
82fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
83if let Some(s) = self.as_known_utf8() {
84 fmt::Display::fmt(s, formatter)
85 } else {
86 fmt::Display::fmt(&**self, formatter)
87 }
88 }
89}
9091#[cfg_attr(test, allow(dead_code))]
92impl Wtf8Buf {
93/// Creates a new, empty WTF-8 string.
94#[inline]
95pub fn new() -> Wtf8Buf {
96Wtf8Buf { bytes: Vec::new(), is_known_utf8: true }
97 }
9899/// Creates a new, empty WTF-8 string with pre-allocated capacity for `capacity` bytes.
100#[inline]
101pub fn with_capacity(capacity: usize) -> Wtf8Buf {
102Wtf8Buf { bytes: Vec::with_capacity(capacity), is_known_utf8: true }
103 }
104105/// 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]
111pub unsafe fn from_bytes_unchecked(value: Vec<u8>) -> Wtf8Buf {
112Wtf8Buf { bytes: value, is_known_utf8: false }
113 }
114115/// 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]
121pub const fn from_string(string: String) -> Wtf8Buf {
122Wtf8Buf { bytes: string.into_bytes(), is_known_utf8: true }
123 }
124125/// 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]
131pub fn from_str(s: &str) -> Wtf8Buf {
132Wtf8Buf { bytes: s.as_bytes().to_vec(), is_known_utf8: true }
133 }
134135pub fn clear(&mut self) {
136self.bytes.clear();
137self.is_known_utf8 = true;
138 }
139140/// 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.
144pub fn from_wide(v: &[u16]) -> Wtf8Buf {
145let mut string = Wtf8Buf::with_capacity(v.len());
146for item in char::decode_utf16(v.iter().cloned()) {
147match item {
148Ok(ch) => string.push_char(ch),
149Err(surrogate) => {
150let surrogate = surrogate.unpaired_surrogate();
151// SAFETY: Surrogates are known to be in the code point range.
152let code_point = unsafe { CodePoint::from_u32_unchecked(surrogate as u32) };
153// The string will now contain an unpaired surrogate.
154string.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.
160unsafe {
161 string.push_code_point_unchecked(code_point);
162 }
163 }
164 }
165 }
166string167 }
168169/// 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.
180unsafe fn push_code_point_unchecked(&mut self, code_point: CodePoint) {
181let mut bytes = [0; char::MAX_LEN_UTF8];
182let bytes = encode_utf8_raw(code_point.to_u32(), &mut bytes);
183self.bytes.extend_from_slice(bytes)
184 }
185186#[inline]
187pub fn as_slice(&self) -> &Wtf8 {
188// SAFETY: `self` maintains `bytes` as well-formed WTF-8.
189unsafe { Wtf8::from_bytes_unchecked(&self.bytes) }
190 }
191192#[inline]
193pub fn as_mut_slice(&mut self) -> &mut Wtf8 {
194// SAFETY: `self` maintains `bytes` as well-formed WTF-8.
195unsafe { Wtf8::from_mut_bytes_unchecked(&mut self.bytes) }
196 }
197198/// Converts the string to UTF-8 without validation, if it was created from
199 /// valid UTF-8.
200#[inline]
201fn as_known_utf8(&self) -> Option<&str> {
202if self.is_known_utf8 {
203// SAFETY: The buffer is known to be valid UTF-8.
204Some(unsafe { str::from_utf8_unchecked(self.as_bytes()) })
205 } else {
206None207 }
208 }
209210/// 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]
218pub fn reserve(&mut self, additional: usize) {
219self.bytes.reserve(additional)
220 }
221222/// 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]
234pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
235self.bytes.try_reserve(additional)
236 }
237238#[inline]
239pub fn reserve_exact(&mut self, additional: usize) {
240self.bytes.reserve_exact(additional)
241 }
242243/// 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]
260pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
261self.bytes.try_reserve_exact(additional)
262 }
263264#[inline]
265pub fn shrink_to_fit(&mut self) {
266self.bytes.shrink_to_fit()
267 }
268269#[inline]
270pub fn shrink_to(&mut self, min_capacity: usize) {
271self.bytes.shrink_to(min_capacity)
272 }
273274#[inline]
275pub fn leak<'a>(self) -> &'a mut Wtf8 {
276// SAFETY: `self` maintains `bytes` as well-formed WTF-8.
277unsafe { Wtf8::from_mut_bytes_unchecked(self.bytes.leak()) }
278 }
279280/// Returns the number of bytes that this string buffer can hold without reallocating.
281#[inline]
282pub fn capacity(&self) -> usize {
283self.bytes.capacity()
284 }
285286/// Append a UTF-8 slice at the end of the string.
287#[inline]
288pub fn push_str(&mut self, other: &str) {
289self.bytes.extend_from_slice(other.as_bytes())
290 }
291292/// 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]
298pub fn push_wtf8(&mut self, other: &Wtf8) {
299match ((*self).final_lead_surrogate(), other.initial_trail_surrogate()) {
300// Replace newly paired surrogates by a supplementary code point.
301(Some(lead), Some(trail)) => {
302let len_without_lead_surrogate = self.len() - 3;
303self.bytes.truncate(len_without_lead_surrogate);
304let other_without_trail_surrogate = &other.as_bytes()[3..];
305// 4 bytes for the supplementary code point
306self.bytes.reserve(4 + other_without_trail_surrogate.len());
307self.push_char(decode_surrogate_pair(lead, trail));
308self.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.
313if self.is_known_utf8 && other.next_surrogate(0).is_some() {
314self.is_known_utf8 = false;
315 }
316317self.bytes.extend_from_slice(other.as_bytes());
318 }
319 }
320 }
321322/// Append a Unicode scalar value at the end of the string.
323#[inline]
324pub fn push_char(&mut self, c: char) {
325// SAFETY: It's always safe to push a char.
326unsafe { self.push_code_point_unchecked(CodePoint::from_char(c)) }
327 }
328329/// 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]
335pub fn push(&mut self, code_point: CodePoint) {
336if let Some(trail) = code_point.to_trail_surrogate() {
337if let Some(lead) = (*self).final_lead_surrogate() {
338let len_without_lead_surrogate = self.len() - 3;
339self.bytes.truncate(len_without_lead_surrogate);
340self.push_char(decode_surrogate_pair(lead, trail));
341return;
342 }
343344// We're pushing a trailing surrogate.
345self.is_known_utf8 = false;
346 } else if code_point.to_lead_surrogate().is_some() {
347// We're pushing a leading surrogate.
348self.is_known_utf8 = false;
349 }
350351// SAFETY: We have checked that no newly paired surrogates at the boundary.
352unsafe { self.push_code_point_unchecked(code_point) }
353 }
354355/// 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]
364pub fn truncate(&mut self, new_len: usize) {
365if new_len <= self.len() {
366if !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));
367self.bytes.truncate(new_len)
368 }
369 }
370371/// Consumes the WTF-8 string and tries to convert it to a vec of bytes.
372#[inline]
373pub fn into_bytes(self) -> Vec<u8> {
374self.bytes
375 }
376377/// 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.
384pub fn into_string(self) -> Result<String, Wtf8Buf> {
385if self.is_known_utf8 || self.next_surrogate(0).is_none() {
386// SAFETY: We have checked that `self.bytes` contains valid UTF-8.
387Ok(unsafe { String::from_utf8_unchecked(self.bytes) })
388 } else {
389Err(self)
390 }
391 }
392393/// 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 “�”)
398pub fn into_string_lossy(mut self) -> String {
399if !self.is_known_utf8 {
400let mut pos = 0;
401while 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.
405self.bytes[surrogate_pos..pos].copy_from_slice("\u{FFFD}".as_bytes());
406 }
407 }
408// SAFETY: Now `self.bytes` contains valid UTF-8.
409unsafe { String::from_utf8_unchecked(self.bytes) }
410 }
411412/// Converts this `Wtf8Buf` into a boxed `Wtf8`.
413#[inline]
414pub 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.
418unsafe { mem::transmute(self.bytes.into_boxed_slice()) }
419 }
420421/// Converts a `Box<Wtf8>` into a `Wtf8Buf`.
422pub 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.
425let bytes: Box<[u8]> = unsafe { mem::transmute(boxed) };
426Wtf8Buf { bytes: bytes.into_vec(), is_known_utf8: false }
427 }
428429/// 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]
440pub unsafe fn extend_from_slice_unchecked(&mut self, other: &[u8]) {
441self.bytes.extend_from_slice(other);
442self.is_known_utf8 = false;
443 }
444}
445446/// 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 {
451fn from_iter<T: IntoIterator<Item = CodePoint>>(iter: T) -> Wtf8Buf {
452let mut string = Wtf8Buf::new();
453string.extend(iter);
454string455 }
456}
457458/// 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 {
463fn extend<T: IntoIterator<Item = CodePoint>>(&mut self, iter: T) {
464let iterator = iter.into_iter();
465let (low, _high) = iterator.size_hint();
466// Lower bound of one byte per code point (ASCII only)
467self.bytes.reserve(low);
468iterator.for_each(move |code_point| self.push(code_point));
469 }
470471#[inline]
472fn extend_one(&mut self, code_point: CodePoint) {
473self.push(code_point);
474 }
475476#[inline]
477fn extend_reserve(&mut self, additional: usize) {
478// Lower bound of one byte per code point (ASCII only)
479self.bytes.reserve(additional);
480 }
481}
482483/// Creates an owned `Wtf8Buf` from a borrowed `Wtf8`.
484pub(super) fn to_owned(slice: &Wtf8) -> Wtf8Buf {
485Wtf8Buf { bytes: slice.as_bytes().to_vec(), is_known_utf8: false }
486}
487488/// 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> {
495let 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.
498return Cow::Borrowed(unsafe { str::from_utf8_unchecked(slice.as_bytes()) });
499 };
500let wtf8_bytes = slice.as_bytes();
501let mut utf8_bytes = Vec::with_capacity(slice.len());
502utf8_bytes.extend_from_slice(&wtf8_bytes[..surrogate_pos]);
503utf8_bytes.extend_from_slice("\u{FFFD}".as_bytes());
504let mut pos = surrogate_pos + 3;
505loop {
506match slice.next_surrogate(pos) {
507Some((surrogate_pos, _)) => {
508utf8_bytes.extend_from_slice(&wtf8_bytes[pos..surrogate_pos]);
509utf8_bytes.extend_from_slice("\u{FFFD}".as_bytes());
510pos = surrogate_pos + 3;
511 }
512None => {
513utf8_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.
516return Cow::Owned(unsafe { String::from_utf8_unchecked(utf8_bytes) });
517 }
518 }
519 }
520}
521522#[inline]
523pub(super) fn clone_into(slice: &Wtf8, buf: &mut Wtf8Buf) {
524buf.is_known_utf8 = false;
525slice.as_bytes().clone_into(&mut buf.bytes);
526}
527528#[cfg(not(test))]
529impl Wtf8 {
530#[rustc_allow_incoherent_impl]
531pub fn to_owned(&self) -> Wtf8Buf {
532to_owned(self)
533 }
534535#[rustc_allow_incoherent_impl]
536pub fn clone_into(&self, buf: &mut Wtf8Buf) {
537clone_into(self, buf)
538 }
539540#[rustc_allow_incoherent_impl]
541pub fn to_string_lossy(&self) -> Cow<'_, str> {
542to_string_lossy(self)
543 }
544545#[rustc_allow_incoherent_impl]
546pub fn into_box(&self) -> Box<Wtf8> {
547let 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.
550unsafe { mem::transmute(boxed) }
551 }
552553#[rustc_allow_incoherent_impl]
554pub fn empty_box() -> Box<Wtf8> {
555let 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.
558unsafe { mem::transmute(boxed) }
559 }
560561#[cfg(target_has_atomic = "ptr")]
562 #[rustc_allow_incoherent_impl]
563pub fn into_arc(&self) -> Arc<Wtf8> {
564let arc: Arc<[u8]> = Arc::from(self.as_bytes());
565// SAFETY: `Wtf8` is a transparent wrapper around `[u8]`.
566unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Wtf8) }
567 }
568569#[rustc_allow_incoherent_impl]
570pub fn into_rc(&self) -> Rc<Wtf8> {
571let rc: Rc<[u8]> = Rc::from(self.as_bytes());
572// SAFETY: `Wtf8` is a transparent wrapper around `[u8]`.
573unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Wtf8) }
574 }
575576#[inline]
577 #[rustc_allow_incoherent_impl]
578pub fn to_ascii_lowercase(&self) -> Wtf8Buf {
579Wtf8Buf { bytes: self.as_bytes().to_ascii_lowercase(), is_known_utf8: false }
580 }
581582#[inline]
583 #[rustc_allow_incoherent_impl]
584pub fn to_ascii_uppercase(&self) -> Wtf8Buf {
585Wtf8Buf { bytes: self.as_bytes().to_ascii_uppercase(), is_known_utf8: false }
586 }
587}
588589#[inline]
590fn decode_surrogate_pair(lead: u16, trail: u16) -> char {
591let 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.
593unsafe { char::from_u32_unchecked(code_point) }
594}
595596impl Hashfor Wtf8Buf {
597#[inline]
598fn hash<H: Hasher>(&self, state: &mut H) {
599state.write(&self.bytes);
6000xfeu8.hash(state)
601 }
602}