core/char/
mod.rs

1//! Utilities for the `char` primitive type.
2//!
3//! *[See also the `char` primitive type](primitive@char).*
4//!
5//! The `char` type represents a single character. More specifically, since
6//! 'character' isn't a well-defined concept in Unicode, `char` is a '[Unicode
7//! scalar value]', which is similar to, but not the same as, a '[Unicode code
8//! point]'.
9//!
10//! [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value
11//! [Unicode code point]: https://www.unicode.org/glossary/#code_point
12//!
13//! This module exists for technical reasons, the primary documentation for
14//! `char` is directly on [the `char` primitive type][char] itself.
15//!
16//! This module is the home of the iterator implementations for the iterators
17//! implemented on `char`, as well as some useful constants and conversion
18//! functions that convert various types to `char`.
19
20#![allow(non_snake_case)]
21#![stable(feature = "rust1", since = "1.0.0")]
22
23mod convert;
24mod decode;
25mod methods;
26
27// stable re-exports
28#[rustfmt::skip]
29#[stable(feature = "try_from", since = "1.34.0")]
30pub use self::convert::CharTryFromError;
31#[stable(feature = "char_from_str", since = "1.20.0")]
32#[cfg(not(feature = "ferrocene_subset"))]
33pub use self::convert::ParseCharError;
34#[stable(feature = "decode_utf16", since = "1.9.0")]
35pub use self::decode::{DecodeUtf16, DecodeUtf16Error};
36
37// perma-unstable re-exports
38#[rustfmt::skip]
39#[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")]
40#[cfg(not(feature = "ferrocene_subset"))]
41pub use self::methods::encode_utf16_raw; // perma-unstable
42#[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")]
43pub use self::methods::{encode_utf8_raw, encode_utf8_raw_unchecked}; // perma-unstable
44
45#[rustfmt::skip]
46use crate::ascii;
47pub(crate) use self::methods::EscapeDebugExtArgs;
48#[cfg(not(feature = "ferrocene_subset"))]
49use crate::error::Error;
50#[cfg(not(feature = "ferrocene_subset"))]
51use crate::escape::{AlwaysEscaped, EscapeIterInner, MaybeEscaped};
52#[cfg(not(feature = "ferrocene_subset"))]
53use crate::fmt::{self, Write};
54#[cfg(not(feature = "ferrocene_subset"))]
55use crate::iter::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce};
56#[cfg(not(feature = "ferrocene_subset"))]
57use crate::num::NonZero;
58
59// Ferrocene addition: imports for certified subset
60#[cfg(feature = "ferrocene_subset")]
61#[rustfmt::skip]
62use crate::{
63    escape::{EscapeIterInner, MaybeEscaped},
64    fmt,
65};
66
67// UTF-8 ranges and tags for encoding characters
68const TAG_CONT: u8 = 0b1000_0000;
69const TAG_TWO_B: u8 = 0b1100_0000;
70const TAG_THREE_B: u8 = 0b1110_0000;
71const TAG_FOUR_B: u8 = 0b1111_0000;
72const MAX_ONE_B: u32 = 0x80;
73const MAX_TWO_B: u32 = 0x800;
74const MAX_THREE_B: u32 = 0x10000;
75
76/*
77    Lu  Uppercase_Letter        an uppercase letter
78    Ll  Lowercase_Letter        a lowercase letter
79    Lt  Titlecase_Letter        a digraphic character, with first part uppercase
80    Lm  Modifier_Letter         a modifier letter
81    Lo  Other_Letter            other letters, including syllables and ideographs
82    Mn  Nonspacing_Mark         a nonspacing combining mark (zero advance width)
83    Mc  Spacing_Mark            a spacing combining mark (positive advance width)
84    Me  Enclosing_Mark          an enclosing combining mark
85    Nd  Decimal_Number          a decimal digit
86    Nl  Letter_Number           a letterlike numeric character
87    No  Other_Number            a numeric character of other type
88    Pc  Connector_Punctuation   a connecting punctuation mark, like a tie
89    Pd  Dash_Punctuation        a dash or hyphen punctuation mark
90    Ps  Open_Punctuation        an opening punctuation mark (of a pair)
91    Pe  Close_Punctuation       a closing punctuation mark (of a pair)
92    Pi  Initial_Punctuation     an initial quotation mark
93    Pf  Final_Punctuation       a final quotation mark
94    Po  Other_Punctuation       a punctuation mark of other type
95    Sm  Math_Symbol             a symbol of primarily mathematical use
96    Sc  Currency_Symbol         a currency sign
97    Sk  Modifier_Symbol         a non-letterlike modifier symbol
98    So  Other_Symbol            a symbol of other type
99    Zs  Space_Separator         a space character (of various non-zero widths)
100    Zl  Line_Separator          U+2028 LINE SEPARATOR only
101    Zp  Paragraph_Separator     U+2029 PARAGRAPH SEPARATOR only
102    Cc  Control                 a C0 or C1 control code
103    Cf  Format                  a format control character
104    Cs  Surrogate               a surrogate code point
105    Co  Private_Use             a private-use character
106    Cn  Unassigned              a reserved unassigned code point or a noncharacter
107*/
108
109/// The highest valid code point a `char` can have, `'\u{10FFFF}'`. Use [`char::MAX`] instead.
110#[stable(feature = "rust1", since = "1.0.0")]
111#[cfg(not(feature = "ferrocene_subset"))]
112pub const MAX: char = char::MAX;
113
114/// The maximum number of bytes required to [encode](char::encode_utf8) a `char` to
115/// UTF-8 encoding.
116#[unstable(feature = "char_max_len", issue = "121714")]
117#[cfg(not(feature = "ferrocene_subset"))]
118pub const MAX_LEN_UTF8: usize = char::MAX_LEN_UTF8;
119
120/// The maximum number of two-byte units required to [encode](char::encode_utf16) a `char`
121/// to UTF-16 encoding.
122#[unstable(feature = "char_max_len", issue = "121714")]
123#[cfg(not(feature = "ferrocene_subset"))]
124pub const MAX_LEN_UTF16: usize = char::MAX_LEN_UTF16;
125
126/// `U+FFFD REPLACEMENT CHARACTER` (�) is used in Unicode to represent a
127/// decoding error. Use [`char::REPLACEMENT_CHARACTER`] instead.
128#[stable(feature = "decode_utf16", since = "1.9.0")]
129#[cfg(not(feature = "ferrocene_subset"))]
130pub const REPLACEMENT_CHARACTER: char = char::REPLACEMENT_CHARACTER;
131
132/// The version of [Unicode](https://www.unicode.org/) that the Unicode parts of
133/// `char` and `str` methods are based on. Use [`char::UNICODE_VERSION`] instead.
134#[stable(feature = "unicode_version", since = "1.45.0")]
135#[cfg(not(feature = "ferrocene_subset"))]
136pub const UNICODE_VERSION: (u8, u8, u8) = char::UNICODE_VERSION;
137
138/// Creates an iterator over the UTF-16 encoded code points in `iter`, returning
139/// unpaired surrogates as `Err`s. Use [`char::decode_utf16`] instead.
140#[stable(feature = "decode_utf16", since = "1.9.0")]
141#[inline]
142#[cfg(not(feature = "ferrocene_subset"))]
143pub fn decode_utf16<I: IntoIterator<Item = u16>>(iter: I) -> DecodeUtf16<I::IntoIter> {
144    self::decode::decode_utf16(iter)
145}
146
147/// Converts a `u32` to a `char`. Use [`char::from_u32`] instead.
148#[stable(feature = "rust1", since = "1.0.0")]
149#[rustc_const_stable(feature = "const_char_convert", since = "1.67.0")]
150#[must_use]
151#[inline]
152#[cfg(not(feature = "ferrocene_subset"))]
153pub const fn from_u32(i: u32) -> Option<char> {
154    self::convert::from_u32(i)
155}
156
157/// Converts a `u32` to a `char`, ignoring validity. Use [`char::from_u32_unchecked`]
158/// instead.
159#[stable(feature = "char_from_unchecked", since = "1.5.0")]
160#[rustc_const_stable(feature = "const_char_from_u32_unchecked", since = "1.81.0")]
161#[must_use]
162#[inline]
163#[cfg(not(feature = "ferrocene_subset"))]
164pub const unsafe fn from_u32_unchecked(i: u32) -> char {
165    // SAFETY: the safety contract must be upheld by the caller.
166    unsafe { self::convert::from_u32_unchecked(i) }
167}
168
169/// Converts a digit in the given radix to a `char`. Use [`char::from_digit`] instead.
170#[stable(feature = "rust1", since = "1.0.0")]
171#[rustc_const_stable(feature = "const_char_convert", since = "1.67.0")]
172#[must_use]
173#[inline]
174#[cfg(not(feature = "ferrocene_subset"))]
175pub const fn from_digit(num: u32, radix: u32) -> Option<char> {
176    self::convert::from_digit(num, radix)
177}
178
179/// Returns an iterator that yields the hexadecimal Unicode escape of a
180/// character, as `char`s.
181///
182/// This `struct` is created by the [`escape_unicode`] method on [`char`]. See
183/// its documentation for more.
184///
185/// [`escape_unicode`]: char::escape_unicode
186#[derive(Clone, Debug)]
187#[stable(feature = "rust1", since = "1.0.0")]
188#[cfg(not(feature = "ferrocene_subset"))]
189pub struct EscapeUnicode(EscapeIterInner<10, AlwaysEscaped>);
190
191#[cfg(not(feature = "ferrocene_subset"))]
192impl EscapeUnicode {
193    #[inline]
194    const fn new(c: char) -> Self {
195        Self(EscapeIterInner::unicode(c))
196    }
197}
198
199#[stable(feature = "rust1", since = "1.0.0")]
200#[cfg(not(feature = "ferrocene_subset"))]
201impl Iterator for EscapeUnicode {
202    type Item = char;
203
204    #[inline]
205    fn next(&mut self) -> Option<char> {
206        self.0.next().map(char::from)
207    }
208
209    #[inline]
210    fn size_hint(&self) -> (usize, Option<usize>) {
211        let n = self.0.len();
212        (n, Some(n))
213    }
214
215    #[inline]
216    fn count(self) -> usize {
217        self.0.len()
218    }
219
220    #[inline]
221    fn last(mut self) -> Option<char> {
222        self.0.next_back().map(char::from)
223    }
224
225    #[inline]
226    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
227        self.0.advance_by(n)
228    }
229}
230
231#[stable(feature = "exact_size_escape", since = "1.11.0")]
232#[cfg(not(feature = "ferrocene_subset"))]
233impl ExactSizeIterator for EscapeUnicode {
234    #[inline]
235    fn len(&self) -> usize {
236        self.0.len()
237    }
238}
239
240#[stable(feature = "fused", since = "1.26.0")]
241#[cfg(not(feature = "ferrocene_subset"))]
242impl FusedIterator for EscapeUnicode {}
243
244#[stable(feature = "char_struct_display", since = "1.16.0")]
245#[cfg(not(feature = "ferrocene_subset"))]
246impl fmt::Display for EscapeUnicode {
247    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
248        fmt::Display::fmt(&self.0, f)
249    }
250}
251
252/// An iterator that yields the literal escape code of a `char`.
253///
254/// This `struct` is created by the [`escape_default`] method on [`char`]. See
255/// its documentation for more.
256///
257/// [`escape_default`]: char::escape_default
258#[derive(Clone, Debug)]
259#[stable(feature = "rust1", since = "1.0.0")]
260#[cfg(not(feature = "ferrocene_subset"))]
261pub struct EscapeDefault(EscapeIterInner<10, AlwaysEscaped>);
262
263#[cfg(not(feature = "ferrocene_subset"))]
264impl EscapeDefault {
265    #[inline]
266    const fn printable(c: ascii::Char) -> Self {
267        Self(EscapeIterInner::ascii(c.to_u8()))
268    }
269
270    #[inline]
271    const fn backslash(c: ascii::Char) -> Self {
272        Self(EscapeIterInner::backslash(c))
273    }
274
275    #[inline]
276    const fn unicode(c: char) -> Self {
277        Self(EscapeIterInner::unicode(c))
278    }
279}
280
281#[stable(feature = "rust1", since = "1.0.0")]
282#[cfg(not(feature = "ferrocene_subset"))]
283impl Iterator for EscapeDefault {
284    type Item = char;
285
286    #[inline]
287    fn next(&mut self) -> Option<char> {
288        self.0.next().map(char::from)
289    }
290
291    #[inline]
292    fn size_hint(&self) -> (usize, Option<usize>) {
293        let n = self.0.len();
294        (n, Some(n))
295    }
296
297    #[inline]
298    fn count(self) -> usize {
299        self.0.len()
300    }
301
302    #[inline]
303    fn last(mut self) -> Option<char> {
304        self.0.next_back().map(char::from)
305    }
306
307    #[inline]
308    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
309        self.0.advance_by(n)
310    }
311}
312
313#[stable(feature = "exact_size_escape", since = "1.11.0")]
314#[cfg(not(feature = "ferrocene_subset"))]
315impl ExactSizeIterator for EscapeDefault {
316    #[inline]
317    fn len(&self) -> usize {
318        self.0.len()
319    }
320}
321
322#[stable(feature = "fused", since = "1.26.0")]
323#[cfg(not(feature = "ferrocene_subset"))]
324impl FusedIterator for EscapeDefault {}
325
326#[stable(feature = "char_struct_display", since = "1.16.0")]
327#[cfg(not(feature = "ferrocene_subset"))]
328impl fmt::Display for EscapeDefault {
329    #[inline]
330    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
331        fmt::Display::fmt(&self.0, f)
332    }
333}
334
335/// An iterator that yields the literal escape code of a `char`.
336///
337/// This `struct` is created by the [`escape_debug`] method on [`char`]. See its
338/// documentation for more.
339///
340/// [`escape_debug`]: char::escape_debug
341#[stable(feature = "char_escape_debug", since = "1.20.0")]
342#[cfg_attr(not(feature = "ferrocene_subset"), derive(Clone, Debug))]
343pub struct EscapeDebug(EscapeIterInner<10, MaybeEscaped>);
344
345impl EscapeDebug {
346    #[inline]
347    const fn printable(chr: char) -> Self {
348        Self(EscapeIterInner::printable(chr))
349    }
350
351    #[inline]
352    const fn backslash(c: ascii::Char) -> Self {
353        Self(EscapeIterInner::backslash(c))
354    }
355
356    #[inline]
357    const fn unicode(c: char) -> Self {
358        Self(EscapeIterInner::unicode(c))
359    }
360}
361
362#[stable(feature = "char_escape_debug", since = "1.20.0")]
363impl Iterator for EscapeDebug {
364    type Item = char;
365
366    #[inline]
367    fn next(&mut self) -> Option<char> {
368        self.0.next()
369    }
370
371    #[inline]
372    fn size_hint(&self) -> (usize, Option<usize>) {
373        let n = self.len();
374        (n, Some(n))
375    }
376
377    #[inline]
378    fn count(self) -> usize {
379        self.len()
380    }
381}
382
383#[stable(feature = "char_escape_debug", since = "1.20.0")]
384impl ExactSizeIterator for EscapeDebug {
385    fn len(&self) -> usize {
386        self.0.len()
387    }
388}
389
390#[stable(feature = "fused", since = "1.26.0")]
391#[cfg(not(feature = "ferrocene_subset"))]
392impl FusedIterator for EscapeDebug {}
393
394#[stable(feature = "char_escape_debug", since = "1.20.0")]
395impl fmt::Display for EscapeDebug {
396    #[inline]
397    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
398        fmt::Display::fmt(&self.0, f)
399    }
400}
401
402#[cfg(not(feature = "ferrocene_subset"))]
403macro_rules! casemappingiter_impls {
404    ($(#[$attr:meta])* $ITER_NAME:ident) => {
405        $(#[$attr])*
406        #[stable(feature = "rust1", since = "1.0.0")]
407        #[derive(Debug, Clone)]
408        pub struct $ITER_NAME(CaseMappingIter);
409
410        #[stable(feature = "rust1", since = "1.0.0")]
411        impl Iterator for $ITER_NAME {
412            type Item = char;
413            fn next(&mut self) -> Option<char> {
414                self.0.next()
415            }
416
417            fn size_hint(&self) -> (usize, Option<usize>) {
418                self.0.size_hint()
419            }
420
421            fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
422            where
423                Fold: FnMut(Acc, Self::Item) -> Acc,
424            {
425                self.0.fold(init, fold)
426            }
427
428            fn count(self) -> usize {
429                self.0.count()
430            }
431
432            fn last(self) -> Option<Self::Item> {
433                self.0.last()
434            }
435
436            fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
437                self.0.advance_by(n)
438            }
439
440            unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
441                // SAFETY: just forwarding requirements to caller
442                unsafe { self.0.__iterator_get_unchecked(idx) }
443            }
444        }
445
446        #[stable(feature = "case_mapping_double_ended", since = "1.59.0")]
447        impl DoubleEndedIterator for $ITER_NAME {
448            fn next_back(&mut self) -> Option<char> {
449                self.0.next_back()
450            }
451
452            fn rfold<Acc, Fold>(self, init: Acc, rfold: Fold) -> Acc
453            where
454                Fold: FnMut(Acc, Self::Item) -> Acc,
455            {
456                self.0.rfold(init, rfold)
457            }
458
459            fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
460                self.0.advance_back_by(n)
461            }
462        }
463
464        #[stable(feature = "fused", since = "1.26.0")]
465        impl FusedIterator for $ITER_NAME {}
466
467        #[stable(feature = "exact_size_case_mapping_iter", since = "1.35.0")]
468        impl ExactSizeIterator for $ITER_NAME {
469            fn len(&self) -> usize {
470                self.0.len()
471            }
472
473            fn is_empty(&self) -> bool {
474                self.0.is_empty()
475            }
476        }
477
478        // SAFETY: forwards to inner `array::IntoIter`
479        #[unstable(feature = "trusted_len", issue = "37572")]
480        unsafe impl TrustedLen for $ITER_NAME {}
481
482        // SAFETY: forwards to inner `array::IntoIter`
483        #[doc(hidden)]
484        #[unstable(feature = "std_internals", issue = "none")]
485        unsafe impl TrustedRandomAccessNoCoerce for $ITER_NAME {
486            const MAY_HAVE_SIDE_EFFECT: bool = false;
487        }
488
489        // SAFETY: this iter has no subtypes/supertypes
490        #[doc(hidden)]
491        #[unstable(feature = "std_internals", issue = "none")]
492        unsafe impl TrustedRandomAccess for $ITER_NAME {}
493
494        #[stable(feature = "char_struct_display", since = "1.16.0")]
495        impl fmt::Display for $ITER_NAME {
496            #[inline]
497            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
498                fmt::Display::fmt(&self.0, f)
499            }
500        }
501    }
502}
503
504#[cfg(not(feature = "ferrocene_subset"))]
505casemappingiter_impls! {
506    /// Returns an iterator that yields the lowercase equivalent of a `char`.
507    ///
508    /// This `struct` is created by the [`to_lowercase`] method on [`char`]. See
509    /// its documentation for more.
510    ///
511    /// [`to_lowercase`]: char::to_lowercase
512    ToLowercase
513}
514
515#[cfg(not(feature = "ferrocene_subset"))]
516casemappingiter_impls! {
517    /// Returns an iterator that yields the uppercase equivalent of a `char`.
518    ///
519    /// This `struct` is created by the [`to_uppercase`] method on [`char`]. See
520    /// its documentation for more.
521    ///
522    /// [`to_uppercase`]: char::to_uppercase
523    ToUppercase
524}
525
526#[derive(Debug, Clone)]
527#[cfg(not(feature = "ferrocene_subset"))]
528struct CaseMappingIter(core::array::IntoIter<char, 3>);
529
530#[cfg(not(feature = "ferrocene_subset"))]
531impl CaseMappingIter {
532    #[inline]
533    fn new(chars: [char; 3]) -> CaseMappingIter {
534        let mut iter = chars.into_iter();
535        if chars[2] == '\0' {
536            iter.next_back();
537            if chars[1] == '\0' {
538                iter.next_back();
539
540                // Deliberately don't check `chars[0]`,
541                // as '\0' lowercases to itself
542            }
543        }
544        CaseMappingIter(iter)
545    }
546}
547
548#[cfg(not(feature = "ferrocene_subset"))]
549impl Iterator for CaseMappingIter {
550    type Item = char;
551
552    fn next(&mut self) -> Option<char> {
553        self.0.next()
554    }
555
556    fn size_hint(&self) -> (usize, Option<usize>) {
557        self.0.size_hint()
558    }
559
560    fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
561    where
562        Fold: FnMut(Acc, Self::Item) -> Acc,
563    {
564        self.0.fold(init, fold)
565    }
566
567    fn count(self) -> usize {
568        self.0.count()
569    }
570
571    fn last(self) -> Option<Self::Item> {
572        self.0.last()
573    }
574
575    fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
576        self.0.advance_by(n)
577    }
578
579    unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item {
580        // SAFETY: just forwarding requirements to caller
581        unsafe { self.0.__iterator_get_unchecked(idx) }
582    }
583}
584
585#[cfg(not(feature = "ferrocene_subset"))]
586impl DoubleEndedIterator for CaseMappingIter {
587    fn next_back(&mut self) -> Option<char> {
588        self.0.next_back()
589    }
590
591    fn rfold<Acc, Fold>(self, init: Acc, rfold: Fold) -> Acc
592    where
593        Fold: FnMut(Acc, Self::Item) -> Acc,
594    {
595        self.0.rfold(init, rfold)
596    }
597
598    fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
599        self.0.advance_back_by(n)
600    }
601}
602
603#[cfg(not(feature = "ferrocene_subset"))]
604impl ExactSizeIterator for CaseMappingIter {
605    fn len(&self) -> usize {
606        self.0.len()
607    }
608
609    fn is_empty(&self) -> bool {
610        self.0.is_empty()
611    }
612}
613
614#[cfg(not(feature = "ferrocene_subset"))]
615impl FusedIterator for CaseMappingIter {}
616
617// SAFETY: forwards to inner `array::IntoIter`
618#[cfg(not(feature = "ferrocene_subset"))]
619unsafe impl TrustedLen for CaseMappingIter {}
620
621// SAFETY: forwards to inner `array::IntoIter`
622#[cfg(not(feature = "ferrocene_subset"))]
623unsafe impl TrustedRandomAccessNoCoerce for CaseMappingIter {
624    const MAY_HAVE_SIDE_EFFECT: bool = false;
625}
626
627// SAFETY: `CaseMappingIter` has no subtypes/supertypes
628#[cfg(not(feature = "ferrocene_subset"))]
629unsafe impl TrustedRandomAccess for CaseMappingIter {}
630
631#[cfg(not(feature = "ferrocene_subset"))]
632impl fmt::Display for CaseMappingIter {
633    #[inline]
634    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
635        for c in self.0.clone() {
636            f.write_char(c)?;
637        }
638        Ok(())
639    }
640}
641
642/// The error type returned when a checked char conversion fails.
643#[stable(feature = "u8_from_char", since = "1.59.0")]
644#[derive(Debug, Copy, Clone, PartialEq, Eq)]
645#[cfg(not(feature = "ferrocene_subset"))]
646pub struct TryFromCharError(pub(crate) ());
647
648#[stable(feature = "u8_from_char", since = "1.59.0")]
649#[cfg(not(feature = "ferrocene_subset"))]
650impl fmt::Display for TryFromCharError {
651    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
652        "unicode code point out of range".fmt(fmt)
653    }
654}
655
656#[stable(feature = "u8_from_char", since = "1.59.0")]
657#[cfg(not(feature = "ferrocene_subset"))]
658impl Error for TryFromCharError {}