]> git.lizzy.rs Git - rust.git/blob - src/librustc_unicode/char.rs
Rollup merge of #27374 - dhuseby:fixing_configure_bsd, r=alexcrichton
[rust.git] / src / librustc_unicode / char.rs
1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! A Unicode scalar value
12 //!
13 //! This module provides the `CharExt` trait, as well as its
14 //! implementation for the primitive `char` type, in order to allow
15 //! basic character manipulation.
16 //!
17 //! A `char` represents a
18 //! *[Unicode scalar
19 //! value](http://www.unicode.org/glossary/#unicode_scalar_value)*, as it can
20 //! contain any Unicode code point except high-surrogate and low-surrogate code
21 //! points.
22 //!
23 //! As such, only values in the ranges \[0x0,0xD7FF\] and \[0xE000,0x10FFFF\]
24 //! (inclusive) are allowed. A `char` can always be safely cast to a `u32`;
25 //! however the converse is not always true due to the above range limits
26 //! and, as such, should be performed via the `from_u32` function.
27 //!
28 //! *[See also the `char` primitive type](../primitive.char.html).*
29
30 #![stable(feature = "rust1", since = "1.0.0")]
31
32 use core::char::CharExt as C;
33 use core::option::Option::{self, Some, None};
34 use core::iter::Iterator;
35 use tables::{derived_property, property, general_category, conversions, charwidth};
36
37 // stable reexports
38 pub use core::char::{MAX, from_u32, from_u32_unchecked, from_digit, EscapeUnicode, EscapeDefault};
39
40 // unstable reexports
41 #[allow(deprecated)]
42 pub use normalize::{decompose_canonical, decompose_compatible, compose};
43 #[allow(deprecated)]
44 pub use tables::normalization::canonical_combining_class;
45 pub use tables::UNICODE_VERSION;
46
47 /// An iterator over the lowercase mapping of a given character, returned from
48 /// the [`to_lowercase` method](../primitive.char.html#method.to_lowercase) on
49 /// characters.
50 #[stable(feature = "rust1", since = "1.0.0")]
51 pub struct ToLowercase(CaseMappingIter);
52
53 #[stable(feature = "rust1", since = "1.0.0")]
54 impl Iterator for ToLowercase {
55     type Item = char;
56     fn next(&mut self) -> Option<char> { self.0.next() }
57 }
58
59 /// An iterator over the uppercase mapping of a given character, returned from
60 /// the [`to_uppercase` method](../primitive.char.html#method.to_uppercase) on
61 /// characters.
62 #[stable(feature = "rust1", since = "1.0.0")]
63 pub struct ToUppercase(CaseMappingIter);
64
65 #[stable(feature = "rust1", since = "1.0.0")]
66 impl Iterator for ToUppercase {
67     type Item = char;
68     fn next(&mut self) -> Option<char> { self.0.next() }
69 }
70
71
72 enum CaseMappingIter {
73     Three(char, char, char),
74     Two(char, char),
75     One(char),
76     Zero
77 }
78
79 impl CaseMappingIter {
80     fn new(chars: [char; 3]) -> CaseMappingIter {
81         if chars[2] == '\0' {
82             if chars[1] == '\0' {
83                 CaseMappingIter::One(chars[0])  // Including if chars[0] == '\0'
84             } else {
85                 CaseMappingIter::Two(chars[0], chars[1])
86             }
87         } else {
88             CaseMappingIter::Three(chars[0], chars[1], chars[2])
89         }
90     }
91 }
92
93 impl Iterator for CaseMappingIter {
94     type Item = char;
95     fn next(&mut self) -> Option<char> {
96         match *self {
97             CaseMappingIter::Three(a, b, c) => {
98                 *self = CaseMappingIter::Two(b, c);
99                 Some(a)
100             }
101             CaseMappingIter::Two(b, c) => {
102                 *self = CaseMappingIter::One(c);
103                 Some(b)
104             }
105             CaseMappingIter::One(c) => {
106                 *self = CaseMappingIter::Zero;
107                 Some(c)
108             }
109             CaseMappingIter::Zero => None,
110         }
111     }
112 }
113
114 #[stable(feature = "rust1", since = "1.0.0")]
115 #[lang = "char"]
116 impl char {
117     /// Checks if a `char` parses as a numeric digit in the given radix.
118     ///
119     /// Compared to `is_numeric()`, this function only recognizes the characters
120     /// `0-9`, `a-z` and `A-Z`.
121     ///
122     /// # Return value
123     ///
124     /// Returns `true` if `c` is a valid digit under `radix`, and `false`
125     /// otherwise.
126     ///
127     /// # Panics
128     ///
129     /// Panics if given a radix > 36.
130     ///
131     /// # Examples
132     ///
133     /// ```
134     /// let c = '1';
135     ///
136     /// assert!(c.is_digit(10));
137     ///
138     /// assert!('f'.is_digit(16));
139     /// ```
140     #[stable(feature = "rust1", since = "1.0.0")]
141     #[inline]
142     pub fn is_digit(self, radix: u32) -> bool { C::is_digit(self, radix) }
143
144     /// Converts a character to the corresponding digit.
145     ///
146     /// # Return value
147     ///
148     /// If `c` is between '0' and '9', the corresponding value between 0 and
149     /// 9. If `c` is 'a' or 'A', 10. If `c` is 'b' or 'B', 11, etc. Returns
150     /// none if the character does not refer to a digit in the given radix.
151     ///
152     /// # Panics
153     ///
154     /// Panics if given a radix outside the range [0..36].
155     ///
156     /// # Examples
157     ///
158     /// ```
159     /// let c = '1';
160     ///
161     /// assert_eq!(c.to_digit(10), Some(1));
162     ///
163     /// assert_eq!('f'.to_digit(16), Some(15));
164     /// ```
165     #[stable(feature = "rust1", since = "1.0.0")]
166     #[inline]
167     pub fn to_digit(self, radix: u32) -> Option<u32> { C::to_digit(self, radix) }
168
169     /// Returns an iterator that yields the hexadecimal Unicode escape of a
170     /// character, as `char`s.
171     ///
172     /// All characters are escaped with Rust syntax of the form `\\u{NNNN}`
173     /// where `NNNN` is the shortest hexadecimal representation of the code
174     /// point.
175     ///
176     /// # Examples
177     ///
178     /// ```
179     /// for c in '❤'.escape_unicode() {
180     ///     print!("{}", c);
181     /// }
182     /// println!("");
183     /// ```
184     ///
185     /// This prints:
186     ///
187     /// ```text
188     /// \u{2764}
189     /// ```
190     ///
191     /// Collecting into a `String`:
192     ///
193     /// ```
194     /// let heart: String = '❤'.escape_unicode().collect();
195     ///
196     /// assert_eq!(heart, r"\u{2764}");
197     /// ```
198     #[stable(feature = "rust1", since = "1.0.0")]
199     #[inline]
200     pub fn escape_unicode(self) -> EscapeUnicode { C::escape_unicode(self) }
201
202     /// Returns an iterator that yields the 'default' ASCII and
203     /// C++11-like literal escape of a character, as `char`s.
204     ///
205     /// The default is chosen with a bias toward producing literals that are
206     /// legal in a variety of languages, including C++11 and similar C-family
207     /// languages. The exact rules are:
208     ///
209     /// * Tab, CR and LF are escaped as '\t', '\r' and '\n' respectively.
210     /// * Single-quote, double-quote and backslash chars are backslash-
211     ///   escaped.
212     /// * Any other chars in the range [0x20,0x7e] are not escaped.
213     /// * Any other chars are given hex Unicode escapes; see `escape_unicode`.
214     ///
215     /// # Examples
216     ///
217     /// ```
218     /// for i in '"'.escape_default() {
219     ///     println!("{}", i);
220     /// }
221     /// ```
222     ///
223     /// This prints:
224     ///
225     /// ```text
226     /// \
227     /// "
228     /// ```
229     ///
230     /// Collecting into a `String`:
231     ///
232     /// ```
233     /// let quote: String = '"'.escape_default().collect();
234     ///
235     /// assert_eq!(quote, "\\\"");
236     /// ```
237     #[stable(feature = "rust1", since = "1.0.0")]
238     #[inline]
239     pub fn escape_default(self) -> EscapeDefault { C::escape_default(self) }
240
241     /// Returns the number of bytes this character would need if encoded in
242     /// UTF-8.
243     ///
244     /// # Examples
245     ///
246     /// ```
247     /// let n = 'ß'.len_utf8();
248     ///
249     /// assert_eq!(n, 2);
250     /// ```
251     #[stable(feature = "rust1", since = "1.0.0")]
252     #[inline]
253     pub fn len_utf8(self) -> usize { C::len_utf8(self) }
254
255     /// Returns the number of 16-bit code units this character would need if
256     /// encoded in UTF-16.
257     ///
258     /// # Examples
259     ///
260     /// ```
261     /// let n = 'ß'.len_utf16();
262     ///
263     /// assert_eq!(n, 1);
264     /// ```
265     #[stable(feature = "rust1", since = "1.0.0")]
266     #[inline]
267     pub fn len_utf16(self) -> usize { C::len_utf16(self) }
268
269     /// Encodes this character as UTF-8 into the provided byte buffer, and then
270     /// returns the number of bytes written.
271     ///
272     /// If the buffer is not large enough, nothing will be written into it and a
273     /// `None` will be returned. A buffer of length four is large enough to
274     /// encode any `char`.
275     ///
276     /// # Examples
277     ///
278     /// In both of these examples, 'ß' takes two bytes to encode.
279     ///
280     /// ```
281     /// #![feature(unicode)]
282     ///
283     /// let mut b = [0; 2];
284     ///
285     /// let result = 'ß'.encode_utf8(&mut b);
286     ///
287     /// assert_eq!(result, Some(2));
288     /// ```
289     ///
290     /// A buffer that's too small:
291     ///
292     /// ```
293     /// #![feature(unicode)]
294     ///
295     /// let mut b = [0; 1];
296     ///
297     /// let result = 'ß'.encode_utf8(&mut b);
298     ///
299     /// assert_eq!(result, None);
300     /// ```
301     #[unstable(feature = "unicode",
302                reason = "pending decision about Iterator/Writer/Reader")]
303     #[inline]
304     pub fn encode_utf8(self, dst: &mut [u8]) -> Option<usize> {
305         C::encode_utf8(self, dst)
306     }
307
308     /// Encodes this character as UTF-16 into the provided `u16` buffer, and
309     /// then returns the number of `u16`s written.
310     ///
311     /// If the buffer is not large enough, nothing will be written into it and a
312     /// `None` will be returned. A buffer of length 2 is large enough to encode
313     /// any `char`.
314     ///
315     /// # Examples
316     ///
317     /// In both of these examples, 'ß' takes one `u16` to encode.
318     ///
319     /// ```
320     /// #![feature(unicode)]
321     ///
322     /// let mut b = [0; 1];
323     ///
324     /// let result = 'ß'.encode_utf16(&mut b);
325     ///
326     /// assert_eq!(result, Some(1));
327     /// ```
328     ///
329     /// A buffer that's too small:
330     ///
331     /// ```
332     /// #![feature(unicode)]
333     ///
334     /// let mut b = [0; 0];
335     ///
336     /// let result = 'ß'.encode_utf8(&mut b);
337     ///
338     /// assert_eq!(result, None);
339     /// ```
340     #[unstable(feature = "unicode",
341                reason = "pending decision about Iterator/Writer/Reader")]
342     #[inline]
343     pub fn encode_utf16(self, dst: &mut [u16]) -> Option<usize> {
344         C::encode_utf16(self, dst)
345     }
346
347     /// Returns whether the specified character is considered a Unicode
348     /// alphabetic code point.
349     #[stable(feature = "rust1", since = "1.0.0")]
350     #[inline]
351     pub fn is_alphabetic(self) -> bool {
352         match self {
353             'a' ... 'z' | 'A' ... 'Z' => true,
354             c if c > '\x7f' => derived_property::Alphabetic(c),
355             _ => false
356         }
357     }
358
359     /// Returns whether the specified character satisfies the 'XID_Start'
360     /// Unicode property.
361     ///
362     /// 'XID_Start' is a Unicode Derived Property specified in
363     /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications),
364     /// mostly similar to ID_Start but modified for closure under NFKx.
365     #[unstable(feature = "unicode",
366                reason = "mainly needed for compiler internals")]
367     #[inline]
368     pub fn is_xid_start(self) -> bool { derived_property::XID_Start(self) }
369
370     /// Returns whether the specified `char` satisfies the 'XID_Continue'
371     /// Unicode property.
372     ///
373     /// 'XID_Continue' is a Unicode Derived Property specified in
374     /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications),
375     /// mostly similar to 'ID_Continue' but modified for closure under NFKx.
376     #[unstable(feature = "unicode",
377                reason = "mainly needed for compiler internals")]
378     #[inline]
379     pub fn is_xid_continue(self) -> bool { derived_property::XID_Continue(self) }
380
381     /// Indicates whether a character is in lowercase.
382     ///
383     /// This is defined according to the terms of the Unicode Derived Core
384     /// Property `Lowercase`.
385     #[stable(feature = "rust1", since = "1.0.0")]
386     #[inline]
387     pub fn is_lowercase(self) -> bool {
388         match self {
389             'a' ... 'z' => true,
390             c if c > '\x7f' => derived_property::Lowercase(c),
391             _ => false
392         }
393     }
394
395     /// Indicates whether a character is in uppercase.
396     ///
397     /// This is defined according to the terms of the Unicode Derived Core
398     /// Property `Uppercase`.
399     #[stable(feature = "rust1", since = "1.0.0")]
400     #[inline]
401     pub fn is_uppercase(self) -> bool {
402         match self {
403             'A' ... 'Z' => true,
404             c if c > '\x7f' => derived_property::Uppercase(c),
405             _ => false
406         }
407     }
408
409     /// Indicates whether a character is whitespace.
410     ///
411     /// Whitespace is defined in terms of the Unicode Property `White_Space`.
412     #[stable(feature = "rust1", since = "1.0.0")]
413     #[inline]
414     pub fn is_whitespace(self) -> bool {
415         match self {
416             ' ' | '\x09' ... '\x0d' => true,
417             c if c > '\x7f' => property::White_Space(c),
418             _ => false
419         }
420     }
421
422     /// Indicates whether a character is alphanumeric.
423     ///
424     /// Alphanumericness is defined in terms of the Unicode General Categories
425     /// 'Nd', 'Nl', 'No' and the Derived Core Property 'Alphabetic'.
426     #[stable(feature = "rust1", since = "1.0.0")]
427     #[inline]
428     pub fn is_alphanumeric(self) -> bool {
429         self.is_alphabetic() || self.is_numeric()
430     }
431
432     /// Indicates whether a character is a control code point.
433     ///
434     /// Control code points are defined in terms of the Unicode General
435     /// Category `Cc`.
436     #[stable(feature = "rust1", since = "1.0.0")]
437     #[inline]
438     pub fn is_control(self) -> bool { general_category::Cc(self) }
439
440     /// Indicates whether the character is numeric (Nd, Nl, or No).
441     #[stable(feature = "rust1", since = "1.0.0")]
442     #[inline]
443     pub fn is_numeric(self) -> bool {
444         match self {
445             '0' ... '9' => true,
446             c if c > '\x7f' => general_category::N(c),
447             _ => false
448         }
449     }
450
451     /// Converts a character to its lowercase equivalent.
452     ///
453     /// This performs complex unconditional mappings with no tailoring.
454     /// See `to_uppercase()` for references and more information.
455     ///
456     /// # Return value
457     ///
458     /// Returns an iterator which yields the characters corresponding to the
459     /// lowercase equivalent of the character. If no conversion is possible then
460     /// an iterator with just the input character is returned.
461     ///
462     /// # Examples
463     ///
464     /// ```
465     /// assert_eq!(Some('c'), 'C'.to_lowercase().next());
466     /// ```
467     #[stable(feature = "rust1", since = "1.0.0")]
468     #[inline]
469     pub fn to_lowercase(self) -> ToLowercase {
470         ToLowercase(CaseMappingIter::new(conversions::to_lower(self)))
471     }
472
473     /// Converts a character to its uppercase equivalent.
474     ///
475     /// This performs complex unconditional mappings with no tailoring:
476     /// it maps one Unicode character to its uppercase equivalent
477     /// according to the Unicode database [1]
478     /// and the additional complex mappings [`SpecialCasing.txt`].
479     /// Conditional mappings (based on context or language) are not considerd here.
480     ///
481     /// A full reference can be found here [2].
482     ///
483     /// # Return value
484     ///
485     /// Returns an iterator which yields the characters corresponding to the
486     /// uppercase equivalent of the character. If no conversion is possible then
487     /// an iterator with just the input character is returned.
488     ///
489     /// [1]: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt
490     ///
491     /// [`SpecialCasing.txt`]: ftp://ftp.unicode.org/Public/UNIDATA/SpecialCasing.txt
492     ///
493     /// [2]: http://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G33992
494     ///
495     /// # Examples
496     ///
497     /// ```
498     /// assert_eq!(Some('C'), 'c'.to_uppercase().next());
499     /// ```
500     #[stable(feature = "rust1", since = "1.0.0")]
501     #[inline]
502     pub fn to_uppercase(self) -> ToUppercase {
503         ToUppercase(CaseMappingIter::new(conversions::to_upper(self)))
504     }
505
506     /// Returns this character's displayed width in columns, or `None` if it is a
507     /// control character other than `'\x00'`.
508     ///
509     /// `is_cjk` determines behavior for characters in the Ambiguous category:
510     /// if `is_cjk` is `true`, these are 2 columns wide; otherwise, they are 1.
511     /// In CJK contexts, `is_cjk` should be `true`, else it should be `false`.
512     /// [Unicode Standard Annex #11](http://www.unicode.org/reports/tr11/)
513     /// recommends that these characters be treated as 1 column (i.e.,
514     /// `is_cjk` = `false`) if the context cannot be reliably determined.
515     #[deprecated(reason = "use the crates.io `unicode-width` library instead",
516                  since = "1.0.0")]
517     #[unstable(feature = "unicode",
518                reason = "needs expert opinion. is_cjk flag stands out as ugly")]
519     #[inline]
520     pub fn width(self, is_cjk: bool) -> Option<usize> {
521         charwidth::width(self, is_cjk)
522     }
523 }