]> git.lizzy.rs Git - rust.git/blob - library/core/src/char/convert.rs
Fix an edge case in `chat::DecodeUtf16::size_hint`
[rust.git] / library / core / src / char / convert.rs
1 //! Character conversions.
2
3 use crate::char::TryFromCharError;
4 use crate::convert::TryFrom;
5 use crate::fmt;
6 use crate::mem::transmute;
7 use crate::str::FromStr;
8
9 use super::MAX;
10
11 /// Converts a `u32` to a `char`.
12 ///
13 /// Note that all [`char`]s are valid [`u32`]s, and can be cast to one with
14 /// `as`:
15 ///
16 /// ```
17 /// let c = '💯';
18 /// let i = c as u32;
19 ///
20 /// assert_eq!(128175, i);
21 /// ```
22 ///
23 /// However, the reverse is not true: not all valid [`u32`]s are valid
24 /// [`char`]s. `from_u32()` will return `None` if the input is not a valid value
25 /// for a [`char`].
26 ///
27 /// For an unsafe version of this function which ignores these checks, see
28 /// [`from_u32_unchecked`].
29 ///
30 /// # Examples
31 ///
32 /// Basic usage:
33 ///
34 /// ```
35 /// use std::char;
36 ///
37 /// let c = char::from_u32(0x2764);
38 ///
39 /// assert_eq!(Some('❤'), c);
40 /// ```
41 ///
42 /// Returning `None` when the input is not a valid [`char`]:
43 ///
44 /// ```
45 /// use std::char;
46 ///
47 /// let c = char::from_u32(0x110000);
48 ///
49 /// assert_eq!(None, c);
50 /// ```
51 #[doc(alias = "chr")]
52 #[must_use]
53 #[inline]
54 #[stable(feature = "rust1", since = "1.0.0")]
55 #[rustc_const_unstable(feature = "const_char_convert", issue = "89259")]
56 pub const fn from_u32(i: u32) -> Option<char> {
57     // FIXME: once Result::ok is const fn, use it here
58     match char_try_from_u32(i) {
59         Ok(c) => Some(c),
60         Err(_) => None,
61     }
62 }
63
64 /// Converts a `u32` to a `char`, ignoring validity.
65 ///
66 /// Note that all [`char`]s are valid [`u32`]s, and can be cast to one with
67 /// `as`:
68 ///
69 /// ```
70 /// let c = '💯';
71 /// let i = c as u32;
72 ///
73 /// assert_eq!(128175, i);
74 /// ```
75 ///
76 /// However, the reverse is not true: not all valid [`u32`]s are valid
77 /// [`char`]s. `from_u32_unchecked()` will ignore this, and blindly cast to
78 /// [`char`], possibly creating an invalid one.
79 ///
80 /// # Safety
81 ///
82 /// This function is unsafe, as it may construct invalid `char` values.
83 ///
84 /// For a safe version of this function, see the [`from_u32`] function.
85 ///
86 /// # Examples
87 ///
88 /// Basic usage:
89 ///
90 /// ```
91 /// use std::char;
92 ///
93 /// let c = unsafe { char::from_u32_unchecked(0x2764) };
94 ///
95 /// assert_eq!('❤', c);
96 /// ```
97 #[inline]
98 #[must_use]
99 #[stable(feature = "char_from_unchecked", since = "1.5.0")]
100 #[rustc_const_unstable(feature = "const_char_convert", issue = "89259")]
101 pub const unsafe fn from_u32_unchecked(i: u32) -> char {
102     // SAFETY: the caller must guarantee that `i` is a valid char value.
103     if cfg!(debug_assertions) { char::from_u32(i).unwrap() } else { unsafe { transmute(i) } }
104 }
105
106 #[stable(feature = "char_convert", since = "1.13.0")]
107 #[rustc_const_unstable(feature = "const_convert", issue = "88674")]
108 impl const From<char> for u32 {
109     /// Converts a [`char`] into a [`u32`].
110     ///
111     /// # Examples
112     ///
113     /// ```
114     /// use std::mem;
115     ///
116     /// let c = 'c';
117     /// let u = u32::from(c);
118     /// assert!(4 == mem::size_of_val(&u))
119     /// ```
120     #[inline]
121     fn from(c: char) -> Self {
122         c as u32
123     }
124 }
125
126 #[stable(feature = "more_char_conversions", since = "1.51.0")]
127 #[rustc_const_unstable(feature = "const_convert", issue = "88674")]
128 impl const From<char> for u64 {
129     /// Converts a [`char`] into a [`u64`].
130     ///
131     /// # Examples
132     ///
133     /// ```
134     /// use std::mem;
135     ///
136     /// let c = '👤';
137     /// let u = u64::from(c);
138     /// assert!(8 == mem::size_of_val(&u))
139     /// ```
140     #[inline]
141     fn from(c: char) -> Self {
142         // The char is casted to the value of the code point, then zero-extended to 64 bit.
143         // See [https://doc.rust-lang.org/reference/expressions/operator-expr.html#semantics]
144         c as u64
145     }
146 }
147
148 #[stable(feature = "more_char_conversions", since = "1.51.0")]
149 #[rustc_const_unstable(feature = "const_convert", issue = "88674")]
150 impl const From<char> for u128 {
151     /// Converts a [`char`] into a [`u128`].
152     ///
153     /// # Examples
154     ///
155     /// ```
156     /// use std::mem;
157     ///
158     /// let c = '⚙';
159     /// let u = u128::from(c);
160     /// assert!(16 == mem::size_of_val(&u))
161     /// ```
162     #[inline]
163     fn from(c: char) -> Self {
164         // The char is casted to the value of the code point, then zero-extended to 128 bit.
165         // See [https://doc.rust-lang.org/reference/expressions/operator-expr.html#semantics]
166         c as u128
167     }
168 }
169
170 /// Map `char` with code point in U+0000..=U+00FF to byte in 0x00..=0xFF with same value, failing
171 /// if the code point is greater than U+00FF.
172 ///
173 /// See [`impl From<u8> for char`](char#impl-From<u8>) for details on the encoding.
174 #[stable(feature = "u8_from_char", since = "1.59.0")]
175 impl TryFrom<char> for u8 {
176     type Error = TryFromCharError;
177
178     #[inline]
179     fn try_from(c: char) -> Result<u8, Self::Error> {
180         u8::try_from(u32::from(c)).map_err(|_| TryFromCharError(()))
181     }
182 }
183
184 /// Maps a byte in 0x00..=0xFF to a `char` whose code point has the same value, in U+0000..=U+00FF.
185 ///
186 /// Unicode is designed such that this effectively decodes bytes
187 /// with the character encoding that IANA calls ISO-8859-1.
188 /// This encoding is compatible with ASCII.
189 ///
190 /// Note that this is different from ISO/IEC 8859-1 a.k.a. ISO 8859-1 (with one less hyphen),
191 /// which leaves some "blanks", byte values that are not assigned to any character.
192 /// ISO-8859-1 (the IANA one) assigns them to the C0 and C1 control codes.
193 ///
194 /// Note that this is *also* different from Windows-1252 a.k.a. code page 1252,
195 /// which is a superset ISO/IEC 8859-1 that assigns some (not all!) blanks
196 /// to punctuation and various Latin characters.
197 ///
198 /// To confuse things further, [on the Web](https://encoding.spec.whatwg.org/)
199 /// `ascii`, `iso-8859-1`, and `windows-1252` are all aliases
200 /// for a superset of Windows-1252 that fills the remaining blanks with corresponding
201 /// C0 and C1 control codes.
202 #[stable(feature = "char_convert", since = "1.13.0")]
203 #[rustc_const_unstable(feature = "const_convert", issue = "88674")]
204 impl const From<u8> for char {
205     /// Converts a [`u8`] into a [`char`].
206     ///
207     /// # Examples
208     ///
209     /// ```
210     /// use std::mem;
211     ///
212     /// let u = 32 as u8;
213     /// let c = char::from(u);
214     /// assert!(4 == mem::size_of_val(&c))
215     /// ```
216     #[inline]
217     fn from(i: u8) -> Self {
218         i as char
219     }
220 }
221
222 /// An error which can be returned when parsing a char.
223 #[stable(feature = "char_from_str", since = "1.20.0")]
224 #[derive(Clone, Debug, PartialEq, Eq)]
225 pub struct ParseCharError {
226     kind: CharErrorKind,
227 }
228
229 impl ParseCharError {
230     #[unstable(
231         feature = "char_error_internals",
232         reason = "this method should not be available publicly",
233         issue = "none"
234     )]
235     #[doc(hidden)]
236     pub fn __description(&self) -> &str {
237         match self.kind {
238             CharErrorKind::EmptyString => "cannot parse char from empty string",
239             CharErrorKind::TooManyChars => "too many characters in string",
240         }
241     }
242 }
243
244 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
245 enum CharErrorKind {
246     EmptyString,
247     TooManyChars,
248 }
249
250 #[stable(feature = "char_from_str", since = "1.20.0")]
251 impl fmt::Display for ParseCharError {
252     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
253         self.__description().fmt(f)
254     }
255 }
256
257 #[stable(feature = "char_from_str", since = "1.20.0")]
258 impl FromStr for char {
259     type Err = ParseCharError;
260
261     #[inline]
262     fn from_str(s: &str) -> Result<Self, Self::Err> {
263         let mut chars = s.chars();
264         match (chars.next(), chars.next()) {
265             (None, _) => Err(ParseCharError { kind: CharErrorKind::EmptyString }),
266             (Some(c), None) => Ok(c),
267             _ => Err(ParseCharError { kind: CharErrorKind::TooManyChars }),
268         }
269     }
270 }
271
272 #[inline]
273 const fn char_try_from_u32(i: u32) -> Result<char, CharTryFromError> {
274     if (i > MAX as u32) || (i >= 0xD800 && i <= 0xDFFF) {
275         Err(CharTryFromError(()))
276     } else {
277         // SAFETY: checked that it's a legal unicode value
278         Ok(unsafe { transmute(i) })
279     }
280 }
281
282 #[stable(feature = "try_from", since = "1.34.0")]
283 impl TryFrom<u32> for char {
284     type Error = CharTryFromError;
285
286     #[inline]
287     fn try_from(i: u32) -> Result<Self, Self::Error> {
288         char_try_from_u32(i)
289     }
290 }
291
292 /// The error type returned when a conversion from u32 to char fails.
293 #[stable(feature = "try_from", since = "1.34.0")]
294 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
295 pub struct CharTryFromError(());
296
297 #[stable(feature = "try_from", since = "1.34.0")]
298 impl fmt::Display for CharTryFromError {
299     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
300         "converted integer out of range for `char`".fmt(f)
301     }
302 }
303
304 /// Converts a digit in the given radix to a `char`.
305 ///
306 /// A 'radix' here is sometimes also called a 'base'. A radix of two
307 /// indicates a binary number, a radix of ten, decimal, and a radix of
308 /// sixteen, hexadecimal, to give some common values. Arbitrary
309 /// radices are supported.
310 ///
311 /// `from_digit()` will return `None` if the input is not a digit in
312 /// the given radix.
313 ///
314 /// # Panics
315 ///
316 /// Panics if given a radix larger than 36.
317 ///
318 /// # Examples
319 ///
320 /// Basic usage:
321 ///
322 /// ```
323 /// use std::char;
324 ///
325 /// let c = char::from_digit(4, 10);
326 ///
327 /// assert_eq!(Some('4'), c);
328 ///
329 /// // Decimal 11 is a single digit in base 16
330 /// let c = char::from_digit(11, 16);
331 ///
332 /// assert_eq!(Some('b'), c);
333 /// ```
334 ///
335 /// Returning `None` when the input is not a digit:
336 ///
337 /// ```
338 /// use std::char;
339 ///
340 /// let c = char::from_digit(20, 10);
341 ///
342 /// assert_eq!(None, c);
343 /// ```
344 ///
345 /// Passing a large radix, causing a panic:
346 ///
347 /// ```should_panic
348 /// use std::char;
349 ///
350 /// // this panics
351 /// let c = char::from_digit(1, 37);
352 /// ```
353 #[inline]
354 #[must_use]
355 #[stable(feature = "rust1", since = "1.0.0")]
356 #[rustc_const_unstable(feature = "const_char_convert", issue = "89259")]
357 pub const fn from_digit(num: u32, radix: u32) -> Option<char> {
358     if radix > 36 {
359         panic!("from_digit: radix is too high (maximum 36)");
360     }
361     if num < radix {
362         let num = num as u8;
363         if num < 10 { Some((b'0' + num) as char) } else { Some((b'a' + num - 10) as char) }
364     } else {
365         None
366     }
367 }