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