]> git.lizzy.rs Git - rust.git/blob - src/libcore/char.rs
rollup merge of #19592: jbranchaud/add-btreemap-iter-doctest
[rust.git] / src / libcore / 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 //! Character manipulation.
12 //!
13 //! For more details, see ::unicode::char (a.k.a. std::char)
14
15 #![allow(non_snake_case)]
16 #![doc(primitive = "char")]
17
18 use mem::transmute;
19 use option::Option;
20 use option::Option::{None, Some};
21 use iter::{range_step, Iterator, RangeStep};
22 use slice::SlicePrelude;
23
24 // UTF-8 ranges and tags for encoding characters
25 static TAG_CONT: u8    = 0b1000_0000u8;
26 static TAG_TWO_B: u8   = 0b1100_0000u8;
27 static TAG_THREE_B: u8 = 0b1110_0000u8;
28 static TAG_FOUR_B: u8  = 0b1111_0000u8;
29 static MAX_ONE_B: u32   =     0x80u32;
30 static MAX_TWO_B: u32   =    0x800u32;
31 static MAX_THREE_B: u32 =  0x10000u32;
32
33 /*
34     Lu  Uppercase_Letter        an uppercase letter
35     Ll  Lowercase_Letter        a lowercase letter
36     Lt  Titlecase_Letter        a digraphic character, with first part uppercase
37     Lm  Modifier_Letter         a modifier letter
38     Lo  Other_Letter            other letters, including syllables and ideographs
39     Mn  Nonspacing_Mark         a nonspacing combining mark (zero advance width)
40     Mc  Spacing_Mark            a spacing combining mark (positive advance width)
41     Me  Enclosing_Mark          an enclosing combining mark
42     Nd  Decimal_Number          a decimal digit
43     Nl  Letter_Number           a letterlike numeric character
44     No  Other_Number            a numeric character of other type
45     Pc  Connector_Punctuation   a connecting punctuation mark, like a tie
46     Pd  Dash_Punctuation        a dash or hyphen punctuation mark
47     Ps  Open_Punctuation        an opening punctuation mark (of a pair)
48     Pe  Close_Punctuation       a closing punctuation mark (of a pair)
49     Pi  Initial_Punctuation     an initial quotation mark
50     Pf  Final_Punctuation       a final quotation mark
51     Po  Other_Punctuation       a punctuation mark of other type
52     Sm  Math_Symbol             a symbol of primarily mathematical use
53     Sc  Currency_Symbol         a currency sign
54     Sk  Modifier_Symbol         a non-letterlike modifier symbol
55     So  Other_Symbol            a symbol of other type
56     Zs  Space_Separator         a space character (of various non-zero widths)
57     Zl  Line_Separator          U+2028 LINE SEPARATOR only
58     Zp  Paragraph_Separator     U+2029 PARAGRAPH SEPARATOR only
59     Cc  Control                 a C0 or C1 control code
60     Cf  Format                  a format control character
61     Cs  Surrogate               a surrogate code point
62     Co  Private_Use             a private-use character
63     Cn  Unassigned              a reserved unassigned code point or a noncharacter
64 */
65
66 /// The highest valid code point
67 #[stable]
68 pub const MAX: char = '\U0010ffff';
69
70 /// Converts from `u32` to a `char`
71 #[inline]
72 #[unstable = "pending decisions about costructors for primitives"]
73 pub fn from_u32(i: u32) -> Option<char> {
74     // catch out-of-bounds and surrogates
75     if (i > MAX as u32) || (i >= 0xD800 && i <= 0xDFFF) {
76         None
77     } else {
78         Some(unsafe { transmute(i) })
79     }
80 }
81
82 ///
83 /// Checks if a `char` parses as a numeric digit in the given radix
84 ///
85 /// Compared to `is_numeric()`, this function only recognizes the
86 /// characters `0-9`, `a-z` and `A-Z`.
87 ///
88 /// # Return value
89 ///
90 /// Returns `true` if `c` is a valid digit under `radix`, and `false`
91 /// otherwise.
92 ///
93 /// # Panics
94 ///
95 /// Panics if given a `radix` > 36.
96 ///
97 /// # Note
98 ///
99 /// This just wraps `to_digit()`.
100 ///
101 #[inline]
102 #[deprecated = "use the Char::is_digit method"]
103 pub fn is_digit_radix(c: char, radix: uint) -> bool {
104     c.is_digit(radix)
105 }
106
107 ///
108 /// Converts a `char` to the corresponding digit
109 ///
110 /// # Return value
111 ///
112 /// If `c` is between '0' and '9', the corresponding value
113 /// between 0 and 9. If `c` is 'a' or 'A', 10. If `c` is
114 /// 'b' or 'B', 11, etc. Returns none if the `char` does not
115 /// refer to a digit in the given radix.
116 ///
117 /// # Panics
118 ///
119 /// Panics if given a `radix` outside the range `[0..36]`.
120 ///
121 #[inline]
122 #[deprecated = "use the Char::to_digit method"]
123 pub fn to_digit(c: char, radix: uint) -> Option<uint> {
124     c.to_digit(radix)
125 }
126
127 ///
128 /// Converts a number to the character representing it
129 ///
130 /// # Return value
131 ///
132 /// Returns `Some(char)` if `num` represents one digit under `radix`,
133 /// using one character of `0-9` or `a-z`, or `None` if it doesn't.
134 ///
135 /// # Panics
136 ///
137 /// Panics if given an `radix` > 36.
138 ///
139 #[inline]
140 #[unstable = "pending decisions about costructors for primitives"]
141 pub fn from_digit(num: uint, radix: uint) -> Option<char> {
142     if radix > 36 {
143         panic!("from_digit: radix is to high (maximum 36)");
144     }
145     if num < radix {
146         unsafe {
147             if num < 10 {
148                 Some(transmute(('0' as uint + num) as u32))
149             } else {
150                 Some(transmute(('a' as uint + num - 10u) as u32))
151             }
152         }
153     } else {
154         None
155     }
156 }
157
158 ///
159 /// Returns the hexadecimal Unicode escape of a `char`
160 ///
161 /// The rules are as follows:
162 ///
163 /// - chars in [0,0xff] get 2-digit escapes: `\\xNN`
164 /// - chars in [0x100,0xffff] get 4-digit escapes: `\\uNNNN`
165 /// - chars above 0x10000 get 8-digit escapes: `\\UNNNNNNNN`
166 ///
167 #[deprecated = "use the Char::escape_unicode method"]
168 pub fn escape_unicode(c: char, f: |char|) {
169     for char in c.escape_unicode() {
170         f(char);
171     }
172 }
173
174 ///
175 /// Returns a 'default' ASCII and C++11-like literal escape of a `char`
176 ///
177 /// The default is chosen with a bias toward producing literals that are
178 /// legal in a variety of languages, including C++11 and similar C-family
179 /// languages. The exact rules are:
180 ///
181 /// - Tab, CR and LF are escaped as '\t', '\r' and '\n' respectively.
182 /// - Single-quote, double-quote and backslash chars are backslash-escaped.
183 /// - Any other chars in the range [0x20,0x7e] are not escaped.
184 /// - Any other chars are given hex Unicode escapes; see `escape_unicode`.
185 ///
186 #[deprecated = "use the Char::escape_default method"]
187 pub fn escape_default(c: char, f: |char|) {
188     for c in c.escape_default() {
189         f(c);
190     }
191 }
192
193 /// Returns the amount of bytes this `char` would need if encoded in UTF-8
194 #[inline]
195 #[deprecated = "use the Char::len_utf8 method"]
196 pub fn len_utf8_bytes(c: char) -> uint {
197     c.len_utf8()
198 }
199
200 /// Basic `char` manipulations.
201 #[experimental = "trait organization may change"]
202 pub trait Char {
203     /// Checks if a `char` parses as a numeric digit in the given radix.
204     ///
205     /// Compared to `is_numeric()`, this function only recognizes the characters
206     /// `0-9`, `a-z` and `A-Z`.
207     ///
208     /// # Return value
209     ///
210     /// Returns `true` if `c` is a valid digit under `radix`, and `false`
211     /// otherwise.
212     ///
213     /// # Panics
214     ///
215     /// Panics if given a radix > 36.
216     #[deprecated = "use is_digit"]
217     fn is_digit_radix(self, radix: uint) -> bool;
218
219     /// Checks if a `char` parses as a numeric digit in the given radix.
220     ///
221     /// Compared to `is_numeric()`, this function only recognizes the characters
222     /// `0-9`, `a-z` and `A-Z`.
223     ///
224     /// # Return value
225     ///
226     /// Returns `true` if `c` is a valid digit under `radix`, and `false`
227     /// otherwise.
228     ///
229     /// # Panics
230     ///
231     /// Panics if given a radix > 36.
232     #[unstable = "pending error conventions"]
233     fn is_digit(self, radix: uint) -> bool;
234
235     /// Converts a character to the corresponding digit.
236     ///
237     /// # Return value
238     ///
239     /// If `c` is between '0' and '9', the corresponding value between 0 and
240     /// 9. If `c` is 'a' or 'A', 10. If `c` is 'b' or 'B', 11, etc. Returns
241     /// none if the character does not refer to a digit in the given radix.
242     ///
243     /// # Panics
244     ///
245     /// Panics if given a radix outside the range [0..36].
246     #[unstable = "pending error conventions, trait organization"]
247     fn to_digit(self, radix: uint) -> Option<uint>;
248
249     /// Converts a number to the character representing it.
250     ///
251     /// # Return value
252     ///
253     /// Returns `Some(char)` if `num` represents one digit under `radix`,
254     /// using one character of `0-9` or `a-z`, or `None` if it doesn't.
255     ///
256     /// # Panics
257     ///
258     /// Panics if given a radix > 36.
259     #[deprecated = "use the char::from_digit free function"]
260     fn from_digit(num: uint, radix: uint) -> Option<Self>;
261
262     /// Converts from `u32` to a `char`
263     #[deprecated = "use the char::from_u32 free function"]
264     fn from_u32(i: u32) -> Option<char>;
265
266     /// Returns an iterator that yields the hexadecimal Unicode escape
267     /// of a character, as `char`s.
268     ///
269     /// The rules are as follows:
270     ///
271     /// * Characters in [0,0xff] get 2-digit escapes: `\\xNN`
272     /// * Characters in [0x100,0xffff] get 4-digit escapes: `\\uNNNN`.
273     /// * Characters above 0x10000 get 8-digit escapes: `\\UNNNNNNNN`.
274     #[unstable = "pending error conventions, trait organization"]
275     fn escape_unicode(self) -> UnicodeEscapedChars;
276
277     /// Returns an iterator that yields the 'default' ASCII and
278     /// C++11-like literal escape of a character, as `char`s.
279     ///
280     /// The default is chosen with a bias toward producing literals that are
281     /// legal in a variety of languages, including C++11 and similar C-family
282     /// languages. The exact rules are:
283     ///
284     /// * Tab, CR and LF are escaped as '\t', '\r' and '\n' respectively.
285     /// * Single-quote, double-quote and backslash chars are backslash-
286     ///   escaped.
287     /// * Any other chars in the range [0x20,0x7e] are not escaped.
288     /// * Any other chars are given hex Unicode escapes; see `escape_unicode`.
289     #[unstable = "pending error conventions, trait organization"]
290     fn escape_default(self) -> DefaultEscapedChars;
291
292     /// Returns the amount of bytes this character would need if encoded in
293     /// UTF-8.
294     #[deprecated = "use len_utf8"]
295     fn len_utf8_bytes(self) -> uint;
296
297     /// Returns the amount of bytes this character would need if encoded in
298     /// UTF-8.
299     #[unstable = "pending trait organization"]
300     fn len_utf8(self) -> uint;
301
302     /// Returns the amount of bytes this character would need if encoded in
303     /// UTF-16.
304     #[unstable = "pending trait organization"]
305     fn len_utf16(self) -> uint;
306
307     /// Encodes this character as UTF-8 into the provided byte buffer,
308     /// and then returns the number of bytes written.
309     ///
310     /// If the buffer is not large enough, nothing will be written into it
311     /// and a `None` will be returned.
312     #[unstable = "pending trait organization"]
313     fn encode_utf8(&self, dst: &mut [u8]) -> Option<uint>;
314
315     /// Encodes this character as UTF-16 into the provided `u16` buffer,
316     /// and then returns the number of `u16`s written.
317     ///
318     /// If the buffer is not large enough, nothing will be written into it
319     /// and a `None` will be returned.
320     #[unstable = "pending trait organization"]
321     fn encode_utf16(&self, dst: &mut [u16]) -> Option<uint>;
322 }
323
324 #[experimental = "trait is experimental"]
325 impl Char for char {
326     #[deprecated = "use is_digit"]
327     fn is_digit_radix(self, radix: uint) -> bool { self.is_digit(radix) }
328
329     #[unstable = "pending trait organization"]
330     fn is_digit(self, radix: uint) -> bool {
331         match self.to_digit(radix) {
332             Some(_) => true,
333             None    => false,
334         }
335     }
336
337     #[unstable = "pending trait organization"]
338     fn to_digit(self, radix: uint) -> Option<uint> {
339         if radix > 36 {
340             panic!("to_digit: radix is too high (maximum 36)");
341         }
342         let val = match self {
343           '0' ... '9' => self as uint - ('0' as uint),
344           'a' ... 'z' => self as uint + 10u - ('a' as uint),
345           'A' ... 'Z' => self as uint + 10u - ('A' as uint),
346           _ => return None,
347         };
348         if val < radix { Some(val) }
349         else { None }
350     }
351
352     #[deprecated = "use the char::from_digit free function"]
353     fn from_digit(num: uint, radix: uint) -> Option<char> { from_digit(num, radix) }
354
355     #[inline]
356     #[deprecated = "use the char::from_u32 free function"]
357     fn from_u32(i: u32) -> Option<char> { from_u32(i) }
358
359     #[unstable = "pending error conventions, trait organization"]
360     fn escape_unicode(self) -> UnicodeEscapedChars {
361         UnicodeEscapedChars { c: self, state: UnicodeEscapedCharsState::Backslash }
362     }
363
364     #[unstable = "pending error conventions, trait organization"]
365     fn escape_default(self) -> DefaultEscapedChars {
366         let init_state = match self {
367             '\t' => DefaultEscapedCharsState::Backslash('t'),
368             '\r' => DefaultEscapedCharsState::Backslash('r'),
369             '\n' => DefaultEscapedCharsState::Backslash('n'),
370             '\\' => DefaultEscapedCharsState::Backslash('\\'),
371             '\'' => DefaultEscapedCharsState::Backslash('\''),
372             '"'  => DefaultEscapedCharsState::Backslash('"'),
373             '\x20' ... '\x7e' => DefaultEscapedCharsState::Char(self),
374             _ => DefaultEscapedCharsState::Unicode(self.escape_unicode())
375         };
376         DefaultEscapedChars { state: init_state }
377     }
378
379     #[inline]
380     #[deprecated = "use len_utf8"]
381     fn len_utf8_bytes(self) -> uint { self.len_utf8() }
382
383     #[inline]
384     #[unstable = "pending trait organization"]
385     fn len_utf8(self) -> uint {
386         let code = self as u32;
387         match () {
388             _ if code < MAX_ONE_B   => 1u,
389             _ if code < MAX_TWO_B   => 2u,
390             _ if code < MAX_THREE_B => 3u,
391             _  => 4u,
392         }
393     }
394
395     #[inline]
396     #[unstable = "pending trait organization"]
397     fn len_utf16(self) -> uint {
398         let ch = self as u32;
399         if (ch & 0xFFFF_u32) == ch { 1 } else { 2 }
400     }
401
402     #[inline]
403     #[unstable = "pending error conventions, trait organization"]
404     fn encode_utf8<'a>(&self, dst: &'a mut [u8]) -> Option<uint> {
405         // Marked #[inline] to allow llvm optimizing it away
406         let code = *self as u32;
407         if code < MAX_ONE_B && dst.len() >= 1 {
408             dst[0] = code as u8;
409             Some(1)
410         } else if code < MAX_TWO_B && dst.len() >= 2 {
411             dst[0] = (code >> 6u & 0x1F_u32) as u8 | TAG_TWO_B;
412             dst[1] = (code & 0x3F_u32) as u8 | TAG_CONT;
413             Some(2)
414         } else if code < MAX_THREE_B && dst.len() >= 3  {
415             dst[0] = (code >> 12u & 0x0F_u32) as u8 | TAG_THREE_B;
416             dst[1] = (code >>  6u & 0x3F_u32) as u8 | TAG_CONT;
417             dst[2] = (code & 0x3F_u32) as u8 | TAG_CONT;
418             Some(3)
419         } else if dst.len() >= 4 {
420             dst[0] = (code >> 18u & 0x07_u32) as u8 | TAG_FOUR_B;
421             dst[1] = (code >> 12u & 0x3F_u32) as u8 | TAG_CONT;
422             dst[2] = (code >>  6u & 0x3F_u32) as u8 | TAG_CONT;
423             dst[3] = (code & 0x3F_u32) as u8 | TAG_CONT;
424             Some(4)
425         } else {
426             None
427         }
428     }
429
430     #[inline]
431     #[unstable = "pending error conventions, trait organization"]
432     fn encode_utf16(&self, dst: &mut [u16]) -> Option<uint> {
433         // Marked #[inline] to allow llvm optimizing it away
434         let mut ch = *self as u32;
435         if (ch & 0xFFFF_u32) == ch  && dst.len() >= 1 {
436             // The BMP falls through (assuming non-surrogate, as it should)
437             dst[0] = ch as u16;
438             Some(1)
439         } else if dst.len() >= 2 {
440             // Supplementary planes break into surrogates.
441             ch -= 0x1_0000_u32;
442             dst[0] = 0xD800_u16 | ((ch >> 10) as u16);
443             dst[1] = 0xDC00_u16 | ((ch as u16) & 0x3FF_u16);
444             Some(2)
445         } else {
446             None
447         }
448     }
449 }
450
451 /// An iterator over the characters that represent a `char`, as escaped by
452 /// Rust's unicode escaping rules.
453 pub struct UnicodeEscapedChars {
454     c: char,
455     state: UnicodeEscapedCharsState
456 }
457
458 enum UnicodeEscapedCharsState {
459     Backslash,
460     Type,
461     Value(RangeStep<i32>),
462 }
463
464 impl Iterator<char> for UnicodeEscapedChars {
465     fn next(&mut self) -> Option<char> {
466         match self.state {
467             UnicodeEscapedCharsState::Backslash => {
468                 self.state = UnicodeEscapedCharsState::Type;
469                 Some('\\')
470             }
471             UnicodeEscapedCharsState::Type => {
472                 let (typechar, pad) = if self.c <= '\x7f' { ('x', 2) }
473                                       else if self.c <= '\uffff' { ('u', 4) }
474                                       else { ('U', 8) };
475                 self.state = UnicodeEscapedCharsState::Value(range_step(4 * (pad - 1), -1, -4i32));
476                 Some(typechar)
477             }
478             UnicodeEscapedCharsState::Value(ref mut range_step) => match range_step.next() {
479                 Some(offset) => {
480                     let offset = offset as uint;
481                     let v = match ((self.c as i32) >> offset) & 0xf {
482                         i @ 0 ... 9 => '0' as i32 + i,
483                         i => 'a' as i32 + (i - 10)
484                     };
485                     Some(unsafe { transmute(v) })
486                 }
487                 None => None
488             }
489         }
490     }
491 }
492
493 /// An iterator over the characters that represent a `char`, escaped
494 /// for maximum portability.
495 pub struct DefaultEscapedChars {
496     state: DefaultEscapedCharsState
497 }
498
499 enum DefaultEscapedCharsState {
500     Backslash(char),
501     Char(char),
502     Done,
503     Unicode(UnicodeEscapedChars),
504 }
505
506 impl Iterator<char> for DefaultEscapedChars {
507     fn next(&mut self) -> Option<char> {
508         match self.state {
509             DefaultEscapedCharsState::Backslash(c) => {
510                 self.state = DefaultEscapedCharsState::Char(c);
511                 Some('\\')
512             }
513             DefaultEscapedCharsState::Char(c) => {
514                 self.state = DefaultEscapedCharsState::Done;
515                 Some(c)
516             }
517             DefaultEscapedCharsState::Done => None,
518             DefaultEscapedCharsState::Unicode(ref mut iter) => iter.next()
519         }
520     }
521 }
522