2014-05-26 01:12:43 +01:00
|
|
|
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
2012-12-03 16:48:01 -08:00
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
Add libunicode; move unicode functions from core
- created new crate, libunicode, below libstd
- split Char trait into Char (libcore) and UnicodeChar (libunicode)
- Unicode-aware functions now live in libunicode
- is_alphabetic, is_XID_start, is_XID_continue, is_lowercase,
is_uppercase, is_whitespace, is_alphanumeric, is_control,
is_digit, to_uppercase, to_lowercase
- added width method in UnicodeChar trait
- determines printed width of character in columns, or None if it is
a non-NULL control character
- takes a boolean argument indicating whether the present context is
CJK or not (characters with 'A'mbiguous widths are double-wide in
CJK contexts, single-wide otherwise)
- split StrSlice into StrSlice (libcore) and UnicodeStrSlice
(libunicode)
- functionality formerly in StrSlice that relied upon Unicode
functionality from Char is now in UnicodeStrSlice
- words, is_whitespace, is_alphanumeric, trim, trim_left, trim_right
- also moved Words type alias into libunicode because words method is
in UnicodeStrSlice
- unified Unicode tables from libcollections, libcore, and libregex into
libunicode
- updated unicode.py in src/etc to generate aforementioned tables
- generated new tables based on latest Unicode data
- added UnicodeChar and UnicodeStrSlice traits to prelude
- libunicode is now the collection point for the std::char module,
combining the libunicode functionality with the Char functionality
from libcore
- thus, moved doc comment for char from core::char to unicode::char
- libcollections remains the collection point for std::str
The Unicode-aware functions that previously lived in the Char and
StrSlice traits are no longer available to programs that only use
libcore. To regain use of these methods, include the libunicode crate
and use the UnicodeChar and/or UnicodeStrSlice traits:
extern crate unicode;
use unicode::UnicodeChar;
use unicode::UnicodeStrSlice;
use unicode::Words; // if you want to use the words() method
NOTE: this does *not* impact programs that use libstd, since UnicodeChar
and UnicodeStrSlice have been added to the prelude.
closes #15224
[breaking-change]
2014-06-30 17:04:10 -04:00
|
|
|
//! Character manipulation.
|
2014-03-07 23:53:34 +01:00
|
|
|
//!
|
2016-11-29 14:38:08 -05:00
|
|
|
//! For more details, see ::std_unicode::char (a.k.a. std::char)
|
2014-03-07 23:53:34 +01:00
|
|
|
|
2014-07-19 00:45:17 +12:00
|
|
|
#![allow(non_snake_case)]
|
2015-06-11 09:54:43 -07:00
|
|
|
#![stable(feature = "core_char", since = "1.2.0")]
|
2011-12-13 16:25:51 -08:00
|
|
|
|
Escape fewer Unicode codepoints in `Debug` impl of `str`
Use the same procedure as Python to determine whether a character is
printable, described in [PEP 3138]. In particular, this means that the
following character classes are escaped:
- Cc (Other, Control)
- Cf (Other, Format)
- Cs (Other, Surrogate), even though they can't appear in Rust strings
- Co (Other, Private Use)
- Cn (Other, Not Assigned)
- Zl (Separator, Line)
- Zp (Separator, Paragraph)
- Zs (Separator, Space), except for the ASCII space `' '` (`0x20`)
This allows for user-friendly inspection of strings that are not
English (e.g. compare `"\u{e9}\u{e8}\u{ea}"` to `"éèê"`).
Fixes #34318.
[PEP 3138]: https://www.python.org/dev/peps/pep-3138/
2016-06-26 15:11:48 +02:00
|
|
|
use char_private::is_printable;
|
2016-08-17 18:01:41 +02:00
|
|
|
use convert::TryFrom;
|
2017-01-07 13:16:03 -05:00
|
|
|
use fmt::{self, Write};
|
2016-09-08 13:54:39 +02:00
|
|
|
use slice;
|
2017-05-27 18:12:16 -04:00
|
|
|
use str::{from_utf8_unchecked_mut, FromStr};
|
2016-08-13 14:42:36 -04:00
|
|
|
use iter::FusedIterator;
|
core: Remove the cast module
This commit revisits the `cast` module in libcore and libstd, and scrutinizes
all functions inside of it. The result was to remove the `cast` module entirely,
folding all functionality into the `mem` module. Specifically, this is the fate
of each function in the `cast` module.
* transmute - This function was moved to `mem`, but it is now marked as
#[unstable]. This is due to planned changes to the `transmute`
function and how it can be invoked (see the #[unstable] comment).
For more information, see RFC 5 and #12898
* transmute_copy - This function was moved to `mem`, with clarification that is
is not an error to invoke it with T/U that are different
sizes, but rather that it is strongly discouraged. This
function is now #[stable]
* forget - This function was moved to `mem` and marked #[stable]
* bump_box_refcount - This function was removed due to the deprecation of
managed boxes as well as its questionable utility.
* transmute_mut - This function was previously deprecated, and removed as part
of this commit.
* transmute_mut_unsafe - This function doesn't serve much of a purpose when it
can be achieved with an `as` in safe code, so it was
removed.
* transmute_lifetime - This function was removed because it is likely a strong
indication that code is incorrect in the first place.
* transmute_mut_lifetime - This function was removed for the same reasons as
`transmute_lifetime`
* copy_lifetime - This function was moved to `mem`, but it is marked
`#[unstable]` now due to the likelihood of being removed in
the future if it is found to not be very useful.
* copy_mut_lifetime - This function was also moved to `mem`, but had the same
treatment as `copy_lifetime`.
* copy_lifetime_vec - This function was removed because it is not used today,
and its existence is not necessary with DST
(copy_lifetime will suffice).
In summary, the cast module was stripped down to these functions, and then the
functions were moved to the `mem` module.
transmute - #[unstable]
transmute_copy - #[stable]
forget - #[stable]
copy_lifetime - #[unstable]
copy_mut_lifetime - #[unstable]
[breaking-change]
2014-05-09 10:34:51 -07:00
|
|
|
use mem::transmute;
|
2014-07-21 20:54:28 -07:00
|
|
|
|
2013-08-10 00:28:47 -07:00
|
|
|
// UTF-8 ranges and tags for encoding characters
|
2015-03-03 10:42:26 +02:00
|
|
|
const TAG_CONT: u8 = 0b1000_0000;
|
|
|
|
const TAG_TWO_B: u8 = 0b1100_0000;
|
|
|
|
const TAG_THREE_B: u8 = 0b1110_0000;
|
|
|
|
const TAG_FOUR_B: u8 = 0b1111_0000;
|
|
|
|
const MAX_ONE_B: u32 = 0x80;
|
|
|
|
const MAX_TWO_B: u32 = 0x800;
|
|
|
|
const MAX_THREE_B: u32 = 0x10000;
|
2013-08-10 00:28:47 -07:00
|
|
|
|
2011-12-23 18:48:08 -08:00
|
|
|
/*
|
2013-05-19 05:53:30 +10:00
|
|
|
Lu Uppercase_Letter an uppercase letter
|
|
|
|
Ll Lowercase_Letter a lowercase letter
|
|
|
|
Lt Titlecase_Letter a digraphic character, with first part uppercase
|
|
|
|
Lm Modifier_Letter a modifier letter
|
|
|
|
Lo Other_Letter other letters, including syllables and ideographs
|
|
|
|
Mn Nonspacing_Mark a nonspacing combining mark (zero advance width)
|
|
|
|
Mc Spacing_Mark a spacing combining mark (positive advance width)
|
|
|
|
Me Enclosing_Mark an enclosing combining mark
|
|
|
|
Nd Decimal_Number a decimal digit
|
|
|
|
Nl Letter_Number a letterlike numeric character
|
|
|
|
No Other_Number a numeric character of other type
|
2011-12-23 18:48:08 -08:00
|
|
|
Pc Connector_Punctuation a connecting punctuation mark, like a tie
|
2013-05-19 05:53:30 +10:00
|
|
|
Pd Dash_Punctuation a dash or hyphen punctuation mark
|
|
|
|
Ps Open_Punctuation an opening punctuation mark (of a pair)
|
|
|
|
Pe Close_Punctuation a closing punctuation mark (of a pair)
|
2011-12-23 18:48:08 -08:00
|
|
|
Pi Initial_Punctuation an initial quotation mark
|
2013-05-19 05:53:30 +10:00
|
|
|
Pf Final_Punctuation a final quotation mark
|
|
|
|
Po Other_Punctuation a punctuation mark of other type
|
|
|
|
Sm Math_Symbol a symbol of primarily mathematical use
|
|
|
|
Sc Currency_Symbol a currency sign
|
|
|
|
Sk Modifier_Symbol a non-letterlike modifier symbol
|
|
|
|
So Other_Symbol a symbol of other type
|
|
|
|
Zs Space_Separator a space character (of various non-zero widths)
|
|
|
|
Zl Line_Separator U+2028 LINE SEPARATOR only
|
2011-12-23 18:48:08 -08:00
|
|
|
Zp Paragraph_Separator U+2029 PARAGRAPH SEPARATOR only
|
2013-05-19 05:53:30 +10:00
|
|
|
Cc Control a C0 or C1 control code
|
|
|
|
Cf Format a format control character
|
|
|
|
Cs Surrogate a surrogate code point
|
|
|
|
Co Private_Use a private-use character
|
|
|
|
Cn Unassigned a reserved unassigned code point or a noncharacter
|
2011-12-23 18:48:08 -08:00
|
|
|
*/
|
|
|
|
|
2015-11-24 11:49:19 -05:00
|
|
|
/// The highest valid code point a `char` can have.
|
|
|
|
///
|
|
|
|
/// A [`char`] is a [Unicode Scalar Value], which means that it is a [Code
|
|
|
|
/// Point], but only ones within a certain range. `MAX` is the highest valid
|
|
|
|
/// code point that's a valid [Unicode Scalar Value].
|
|
|
|
///
|
2016-03-07 23:55:52 -08:00
|
|
|
/// [`char`]: ../../std/primitive.char.html
|
2015-11-24 11:49:19 -05:00
|
|
|
/// [Unicode Scalar Value]: http://www.unicode.org/glossary/#unicode_scalar_value
|
|
|
|
/// [Code Point]: http://www.unicode.org/glossary/#code_point
|
2015-01-23 21:48:20 -08:00
|
|
|
#[stable(feature = "rust1", since = "1.0.0")]
|
2014-12-09 14:08:10 -08:00
|
|
|
pub const MAX: char = '\u{10ffff}';
|
2013-09-03 19:24:12 -04:00
|
|
|
|
2015-11-24 11:49:19 -05:00
|
|
|
/// Converts a `u32` to a `char`.
|
|
|
|
///
|
|
|
|
/// Note that all [`char`]s are valid [`u32`]s, and can be casted to one with
|
|
|
|
/// [`as`]:
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// let c = '💯';
|
|
|
|
/// let i = c as u32;
|
|
|
|
///
|
|
|
|
/// assert_eq!(128175, i);
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// However, the reverse is not true: not all valid [`u32`]s are valid
|
|
|
|
/// [`char`]s. `from_u32()` will return `None` if the input is not a valid value
|
|
|
|
/// for a [`char`].
|
|
|
|
///
|
2016-03-07 23:55:52 -08:00
|
|
|
/// [`char`]: ../../std/primitive.char.html
|
|
|
|
/// [`u32`]: ../../std/primitive.u32.html
|
2017-03-15 12:13:55 -04:00
|
|
|
/// [`as`]: ../../book/first-edition/casting-between-types.html#as
|
2015-11-24 11:49:19 -05:00
|
|
|
///
|
|
|
|
/// For an unsafe version of this function which ignores these checks, see
|
2017-03-12 14:04:52 -04:00
|
|
|
/// [`from_u32_unchecked`].
|
2015-11-24 11:49:19 -05:00
|
|
|
///
|
2017-03-12 14:04:52 -04:00
|
|
|
/// [`from_u32_unchecked`]: fn.from_u32_unchecked.html
|
2015-01-23 16:43:16 -05:00
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
2015-11-24 11:49:19 -05:00
|
|
|
/// Basic usage:
|
|
|
|
///
|
2015-01-23 16:43:16 -05:00
|
|
|
/// ```
|
|
|
|
/// use std::char;
|
|
|
|
///
|
2015-11-24 11:49:19 -05:00
|
|
|
/// let c = char::from_u32(0x2764);
|
|
|
|
///
|
|
|
|
/// assert_eq!(Some('❤'), c);
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Returning `None` when the input is not a valid [`char`]:
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use std::char;
|
|
|
|
///
|
|
|
|
/// let c = char::from_u32(0x110000);
|
|
|
|
///
|
|
|
|
/// assert_eq!(None, c);
|
2015-01-23 16:43:16 -05:00
|
|
|
/// ```
|
2014-02-23 09:11:36 +11:00
|
|
|
#[inline]
|
2015-01-23 21:48:20 -08:00
|
|
|
#[stable(feature = "rust1", since = "1.0.0")]
|
2013-09-03 19:24:12 -04:00
|
|
|
pub fn from_u32(i: u32) -> Option<char> {
|
2016-08-17 18:01:41 +02:00
|
|
|
char::try_from(i).ok()
|
2013-09-03 19:24:12 -04:00
|
|
|
}
|
|
|
|
|
2015-11-24 11:49:19 -05:00
|
|
|
/// Converts a `u32` to a `char`, ignoring validity.
|
|
|
|
///
|
|
|
|
/// Note that all [`char`]s are valid [`u32`]s, and can be casted to one with
|
|
|
|
/// [`as`]:
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// let c = '💯';
|
|
|
|
/// let i = c as u32;
|
|
|
|
///
|
|
|
|
/// assert_eq!(128175, i);
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// However, the reverse is not true: not all valid [`u32`]s are valid
|
|
|
|
/// [`char`]s. `from_u32_unchecked()` will ignore this, and blindly cast to
|
|
|
|
/// [`char`], possibly creating an invalid one.
|
|
|
|
///
|
2016-03-07 23:55:52 -08:00
|
|
|
/// [`char`]: ../../std/primitive.char.html
|
|
|
|
/// [`u32`]: ../../std/primitive.u32.html
|
2017-03-15 12:13:55 -04:00
|
|
|
/// [`as`]: ../../book/first-edition/casting-between-types.html#as
|
2015-11-24 11:49:19 -05:00
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
///
|
|
|
|
/// This function is unsafe, as it may construct invalid `char` values.
|
|
|
|
///
|
2017-03-12 14:04:52 -04:00
|
|
|
/// For a safe version of this function, see the [`from_u32`] function.
|
2015-11-24 11:49:19 -05:00
|
|
|
///
|
2017-03-12 14:04:52 -04:00
|
|
|
/// [`from_u32`]: fn.from_u32.html
|
2015-11-24 11:49:19 -05:00
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// Basic usage:
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use std::char;
|
|
|
|
///
|
|
|
|
/// let c = unsafe { char::from_u32_unchecked(0x2764) };
|
|
|
|
///
|
|
|
|
/// assert_eq!('❤', c);
|
|
|
|
/// ```
|
2015-07-23 12:24:27 +02:00
|
|
|
#[inline]
|
std: Stabilize library APIs for 1.5
This commit stabilizes and deprecates library APIs whose FCP has closed in the
last cycle, specifically:
Stabilized APIs:
* `fs::canonicalize`
* `Path::{metadata, symlink_metadata, canonicalize, read_link, read_dir, exists,
is_file, is_dir}` - all moved to inherent methods from the `PathExt` trait.
* `Formatter::fill`
* `Formatter::width`
* `Formatter::precision`
* `Formatter::sign_plus`
* `Formatter::sign_minus`
* `Formatter::alternate`
* `Formatter::sign_aware_zero_pad`
* `string::ParseError`
* `Utf8Error::valid_up_to`
* `Iterator::{cmp, partial_cmp, eq, ne, lt, le, gt, ge}`
* `<[T]>::split_{first,last}{,_mut}`
* `Condvar::wait_timeout` - note that `wait_timeout_ms` is not yet deprecated
but will be once 1.5 is released.
* `str::{R,}MatchIndices`
* `str::{r,}match_indices`
* `char::from_u32_unchecked`
* `VecDeque::insert`
* `VecDeque::shrink_to_fit`
* `VecDeque::as_slices`
* `VecDeque::as_mut_slices`
* `VecDeque::swap_remove_front` - (renamed from `swap_front_remove`)
* `VecDeque::swap_remove_back` - (renamed from `swap_back_remove`)
* `Vec::resize`
* `str::slice_mut_unchecked`
* `FileTypeExt`
* `FileTypeExt::{is_block_device, is_char_device, is_fifo, is_socket}`
* `BinaryHeap::from` - `from_vec` deprecated in favor of this
* `BinaryHeap::into_vec` - plus a `Into` impl
* `BinaryHeap::into_sorted_vec`
Deprecated APIs
* `slice::ref_slice`
* `slice::mut_ref_slice`
* `iter::{range_inclusive, RangeInclusive}`
* `std::dynamic_lib`
Closes #27706
Closes #27725
cc #27726 (align not stabilized yet)
Closes #27734
Closes #27737
Closes #27742
Closes #27743
Closes #27772
Closes #27774
Closes #27777
Closes #27781
cc #27788 (a few remaining methods though)
Closes #27790
Closes #27793
Closes #27796
Closes #27810
cc #28147 (not all parts stabilized)
2015-10-22 16:28:45 -07:00
|
|
|
#[stable(feature = "char_from_unchecked", since = "1.5.0")]
|
2015-07-23 12:24:27 +02:00
|
|
|
pub unsafe fn from_u32_unchecked(i: u32) -> char {
|
|
|
|
transmute(i)
|
|
|
|
}
|
|
|
|
|
2016-08-17 17:41:33 +02:00
|
|
|
#[stable(feature = "char_convert", since = "1.13.0")]
|
|
|
|
impl From<char> for u32 {
|
|
|
|
#[inline]
|
|
|
|
fn from(c: char) -> Self {
|
|
|
|
c as u32
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Maps a byte in 0x00...0xFF to a `char` whose code point has the same value, in U+0000 to U+00FF.
|
|
|
|
///
|
|
|
|
/// Unicode is designed such that this effectively decodes bytes
|
|
|
|
/// with the character encoding that IANA calls ISO-8859-1.
|
|
|
|
/// This encoding is compatible with ASCII.
|
|
|
|
///
|
2017-03-29 16:50:09 +05:30
|
|
|
/// Note that this is different from ISO/IEC 8859-1 a.k.a. ISO 8859-1 (with one less hyphen),
|
2016-08-17 17:41:33 +02:00
|
|
|
/// which leaves some "blanks", byte values that are not assigned to any character.
|
|
|
|
/// ISO-8859-1 (the IANA one) assigns them to the C0 and C1 control codes.
|
|
|
|
///
|
|
|
|
/// Note that this is *also* different from Windows-1252 a.k.a. code page 1252,
|
|
|
|
/// which is a superset ISO/IEC 8859-1 that assigns some (not all!) blanks
|
|
|
|
/// to punctuation and various Latin characters.
|
|
|
|
///
|
|
|
|
/// To confuse things further, [on the Web](https://encoding.spec.whatwg.org/)
|
|
|
|
/// `ascii`, `iso-8859-1`, and `windows-1252` are all aliases
|
|
|
|
/// for a superset of Windows-1252 that fills the remaining blanks with corresponding
|
|
|
|
/// C0 and C1 control codes.
|
|
|
|
#[stable(feature = "char_convert", since = "1.13.0")]
|
|
|
|
impl From<u8> for char {
|
|
|
|
#[inline]
|
|
|
|
fn from(i: u8) -> Self {
|
|
|
|
i as char
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-27 18:12:16 -04:00
|
|
|
|
|
|
|
/// An error which can be returned when parsing a char.
|
2017-07-10 02:07:29 +01:00
|
|
|
#[stable(feature = "char_from_str", since = "1.20.0")]
|
2018-01-26 18:52:27 -05:00
|
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
2017-05-27 18:12:16 -04:00
|
|
|
pub struct ParseCharError {
|
|
|
|
kind: CharErrorKind,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ParseCharError {
|
|
|
|
#[unstable(feature = "char_error_internals",
|
|
|
|
reason = "this method should not be available publicly",
|
|
|
|
issue = "0")]
|
|
|
|
#[doc(hidden)]
|
|
|
|
pub fn __description(&self) -> &str {
|
|
|
|
match self.kind {
|
|
|
|
CharErrorKind::EmptyString => {
|
|
|
|
"cannot parse char from empty string"
|
|
|
|
},
|
|
|
|
CharErrorKind::TooManyChars => "too many characters in string"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
|
|
|
enum CharErrorKind {
|
|
|
|
EmptyString,
|
|
|
|
TooManyChars,
|
|
|
|
}
|
|
|
|
|
2017-07-10 02:07:29 +01:00
|
|
|
#[stable(feature = "char_from_str", since = "1.20.0")]
|
2017-05-27 18:12:16 -04:00
|
|
|
impl fmt::Display for ParseCharError {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
self.__description().fmt(f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-10 02:07:29 +01:00
|
|
|
#[stable(feature = "char_from_str", since = "1.20.0")]
|
2017-05-27 18:12:16 -04:00
|
|
|
impl FromStr for char {
|
|
|
|
type Err = ParseCharError;
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
|
|
let mut chars = s.chars();
|
|
|
|
match (chars.next(), chars.next()) {
|
|
|
|
(None, _) => {
|
|
|
|
Err(ParseCharError { kind: CharErrorKind::EmptyString })
|
|
|
|
},
|
|
|
|
(Some(c), None) => Ok(c),
|
|
|
|
_ => {
|
|
|
|
Err(ParseCharError { kind: CharErrorKind::TooManyChars })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-08-17 18:01:41 +02:00
|
|
|
#[unstable(feature = "try_from", issue = "33417")]
|
|
|
|
impl TryFrom<u32> for char {
|
2017-03-05 13:00:32 -08:00
|
|
|
type Error = CharTryFromError;
|
2016-08-17 18:01:41 +02:00
|
|
|
|
|
|
|
#[inline]
|
2017-03-05 13:00:32 -08:00
|
|
|
fn try_from(i: u32) -> Result<Self, Self::Error> {
|
2016-08-17 18:01:41 +02:00
|
|
|
if (i > MAX as u32) || (i >= 0xD800 && i <= 0xDFFF) {
|
|
|
|
Err(CharTryFromError(()))
|
|
|
|
} else {
|
|
|
|
Ok(unsafe { from_u32_unchecked(i) })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// The error type returned when a conversion from u32 to char fails.
|
|
|
|
#[unstable(feature = "try_from", issue = "33417")]
|
|
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
|
|
|
pub struct CharTryFromError(());
|
|
|
|
|
|
|
|
#[unstable(feature = "try_from", issue = "33417")]
|
|
|
|
impl fmt::Display for CharTryFromError {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
"converted integer out of range for `char`".fmt(f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-24 11:49:19 -05:00
|
|
|
/// Converts a digit in the given radix to a `char`.
|
2013-05-19 06:03:40 +10:00
|
|
|
///
|
2015-11-24 11:49:19 -05:00
|
|
|
/// A 'radix' here is sometimes also called a 'base'. A radix of two
|
|
|
|
/// indicates a binary number, a radix of ten, decimal, and a radix of
|
2016-01-05 07:40:40 -08:00
|
|
|
/// sixteen, hexadecimal, to give some common values. Arbitrary
|
2016-11-23 08:49:35 -05:00
|
|
|
/// radices are supported.
|
2013-05-19 06:03:40 +10:00
|
|
|
///
|
2015-11-24 11:49:19 -05:00
|
|
|
/// `from_digit()` will return `None` if the input is not a digit in
|
|
|
|
/// the given radix.
|
2013-05-19 06:03:40 +10:00
|
|
|
///
|
2014-11-12 03:36:09 +09:00
|
|
|
/// # Panics
|
2013-05-19 06:03:40 +10:00
|
|
|
///
|
2015-11-24 11:49:19 -05:00
|
|
|
/// Panics if given a radix larger than 36.
|
2013-05-19 06:03:40 +10:00
|
|
|
///
|
2015-01-23 16:43:16 -05:00
|
|
|
/// # Examples
|
|
|
|
///
|
2015-11-24 11:49:19 -05:00
|
|
|
/// Basic usage:
|
|
|
|
///
|
2015-01-23 16:43:16 -05:00
|
|
|
/// ```
|
|
|
|
/// use std::char;
|
|
|
|
///
|
|
|
|
/// let c = char::from_digit(4, 10);
|
|
|
|
///
|
2015-11-24 11:49:19 -05:00
|
|
|
/// assert_eq!(Some('4'), c);
|
|
|
|
///
|
|
|
|
/// // Decimal 11 is a single digit in base 16
|
|
|
|
/// let c = char::from_digit(11, 16);
|
|
|
|
///
|
|
|
|
/// assert_eq!(Some('b'), c);
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Returning `None` when the input is not a digit:
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use std::char;
|
|
|
|
///
|
|
|
|
/// let c = char::from_digit(20, 10);
|
|
|
|
///
|
|
|
|
/// assert_eq!(None, c);
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Passing a large radix, causing a panic:
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use std::thread;
|
|
|
|
/// use std::char;
|
|
|
|
///
|
|
|
|
/// let result = thread::spawn(|| {
|
|
|
|
/// // this panics
|
|
|
|
/// let c = char::from_digit(1, 37);
|
|
|
|
/// }).join();
|
|
|
|
///
|
|
|
|
/// assert!(result.is_err());
|
2015-01-23 16:43:16 -05:00
|
|
|
/// ```
|
2013-01-20 21:28:12 +01:00
|
|
|
#[inline]
|
2015-03-05 18:23:57 -08:00
|
|
|
#[stable(feature = "rust1", since = "1.0.0")]
|
2015-02-15 00:09:40 +03:00
|
|
|
pub fn from_digit(num: u32, radix: u32) -> Option<char> {
|
2013-01-20 21:28:12 +01:00
|
|
|
if radix > 36 {
|
2014-12-14 00:48:09 -05:00
|
|
|
panic!("from_digit: radix is too high (maximum 36)");
|
2013-01-20 21:28:12 +01:00
|
|
|
}
|
|
|
|
if num < radix {
|
2015-07-23 12:24:27 +02:00
|
|
|
let num = num as u8;
|
|
|
|
if num < 10 {
|
|
|
|
Some((b'0' + num) as char)
|
|
|
|
} else {
|
|
|
|
Some((b'a' + num - 10) as char)
|
2013-01-20 21:28:12 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-05 18:23:57 -08:00
|
|
|
// NB: the stabilization and documentation for this trait is in
|
|
|
|
// unicode/char.rs, not here
|
|
|
|
#[allow(missing_docs)] // docs in libunicode/u_char.rs
|
2015-04-07 17:15:58 -07:00
|
|
|
#[doc(hidden)]
|
2015-06-09 11:18:03 -07:00
|
|
|
#[unstable(feature = "core_char_ext",
|
2015-08-12 17:23:48 -07:00
|
|
|
reason = "the stable interface is `impl char` in later crate",
|
2016-03-07 16:34:35 -08:00
|
|
|
issue = "32110")]
|
2014-12-30 13:53:20 +11:00
|
|
|
pub trait CharExt {
|
2015-12-02 17:31:49 -08:00
|
|
|
#[stable(feature = "core", since = "1.6.0")]
|
2015-02-15 00:09:40 +03:00
|
|
|
fn is_digit(self, radix: u32) -> bool;
|
2015-12-02 17:31:49 -08:00
|
|
|
#[stable(feature = "core", since = "1.6.0")]
|
2015-02-15 00:09:40 +03:00
|
|
|
fn to_digit(self, radix: u32) -> Option<u32>;
|
2015-12-02 17:31:49 -08:00
|
|
|
#[stable(feature = "core", since = "1.6.0")]
|
2014-12-15 08:49:01 -08:00
|
|
|
fn escape_unicode(self) -> EscapeUnicode;
|
2015-12-02 17:31:49 -08:00
|
|
|
#[stable(feature = "core", since = "1.6.0")]
|
2014-12-15 08:49:01 -08:00
|
|
|
fn escape_default(self) -> EscapeDefault;
|
2017-07-20 15:38:59 -07:00
|
|
|
#[stable(feature = "char_escape_debug", since = "1.20.0")]
|
2016-07-27 12:10:31 +02:00
|
|
|
fn escape_debug(self) -> EscapeDebug;
|
2015-12-02 17:31:49 -08:00
|
|
|
#[stable(feature = "core", since = "1.6.0")]
|
2015-02-15 00:09:40 +03:00
|
|
|
fn len_utf8(self) -> usize;
|
2015-12-02 17:31:49 -08:00
|
|
|
#[stable(feature = "core", since = "1.6.0")]
|
2015-02-15 00:09:40 +03:00
|
|
|
fn len_utf16(self) -> usize;
|
2016-12-14 12:34:02 -08:00
|
|
|
#[stable(feature = "unicode_encode_char", since = "1.15.0")]
|
2016-09-08 13:54:39 +02:00
|
|
|
fn encode_utf8(self, dst: &mut [u8]) -> &mut str;
|
2016-12-14 12:34:02 -08:00
|
|
|
#[stable(feature = "unicode_encode_char", since = "1.15.0")]
|
2016-09-08 13:54:39 +02:00
|
|
|
fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16];
|
2013-05-19 05:50:02 +10:00
|
|
|
}
|
|
|
|
|
2015-12-02 17:31:49 -08:00
|
|
|
#[stable(feature = "core", since = "1.6.0")]
|
2014-12-30 13:36:24 +11:00
|
|
|
impl CharExt for char {
|
2015-06-09 23:58:00 +02:00
|
|
|
#[inline]
|
2015-02-15 00:09:40 +03:00
|
|
|
fn is_digit(self, radix: u32) -> bool {
|
2015-01-04 01:19:03 +11:00
|
|
|
self.to_digit(radix).is_some()
|
2014-10-13 13:03:42 -07:00
|
|
|
}
|
2014-10-08 17:24:15 -07:00
|
|
|
|
2015-06-09 23:58:00 +02:00
|
|
|
#[inline]
|
2015-02-15 00:09:40 +03:00
|
|
|
fn to_digit(self, radix: u32) -> Option<u32> {
|
2014-10-13 13:03:42 -07:00
|
|
|
if radix > 36 {
|
|
|
|
panic!("to_digit: radix is too high (maximum 36)");
|
|
|
|
}
|
2014-10-14 13:08:54 -07:00
|
|
|
let val = match self {
|
2015-02-15 00:09:40 +03:00
|
|
|
'0' ... '9' => self as u32 - '0' as u32,
|
|
|
|
'a' ... 'z' => self as u32 - 'a' as u32 + 10,
|
|
|
|
'A' ... 'Z' => self as u32 - 'A' as u32 + 10,
|
2014-10-13 13:03:42 -07:00
|
|
|
_ => return None,
|
|
|
|
};
|
|
|
|
if val < radix { Some(val) }
|
|
|
|
else { None }
|
|
|
|
}
|
2013-05-19 05:50:02 +10:00
|
|
|
|
2015-06-09 23:58:00 +02:00
|
|
|
#[inline]
|
2014-12-15 08:49:01 -08:00
|
|
|
fn escape_unicode(self) -> EscapeUnicode {
|
2015-12-30 22:03:35 +01:00
|
|
|
let c = self as u32;
|
2016-01-28 15:12:16 +01:00
|
|
|
|
2015-12-30 22:03:35 +01:00
|
|
|
// or-ing 1 ensures that for c==0 the code computes that one
|
|
|
|
// digit should be printed and (which is the same) avoids the
|
|
|
|
// (31 - 32) underflow
|
|
|
|
let msb = 31 - (c | 1).leading_zeros();
|
2016-01-28 15:12:16 +01:00
|
|
|
|
|
|
|
// the index of the most significant hex digit
|
|
|
|
let ms_hex_digit = msb / 4;
|
2015-12-30 21:45:24 +01:00
|
|
|
EscapeUnicode {
|
|
|
|
c: self,
|
|
|
|
state: EscapeUnicodeState::Backslash,
|
2016-01-28 15:12:16 +01:00
|
|
|
hex_digit_idx: ms_hex_digit as usize,
|
2015-12-30 21:45:24 +01:00
|
|
|
}
|
2014-10-13 13:03:42 -07:00
|
|
|
}
|
2013-05-19 05:50:02 +10:00
|
|
|
|
2015-06-09 23:58:00 +02:00
|
|
|
#[inline]
|
2014-12-15 08:49:01 -08:00
|
|
|
fn escape_default(self) -> EscapeDefault {
|
2016-07-26 01:39:54 +02:00
|
|
|
let init_state = match self {
|
|
|
|
'\t' => EscapeDefaultState::Backslash('t'),
|
|
|
|
'\r' => EscapeDefaultState::Backslash('r'),
|
|
|
|
'\n' => EscapeDefaultState::Backslash('n'),
|
|
|
|
'\\' | '\'' | '"' => EscapeDefaultState::Backslash(self),
|
|
|
|
'\x20' ... '\x7e' => EscapeDefaultState::Char(self),
|
|
|
|
_ => EscapeDefaultState::Unicode(self.escape_unicode())
|
|
|
|
};
|
|
|
|
EscapeDefault { state: init_state }
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
2016-07-27 12:10:31 +02:00
|
|
|
fn escape_debug(self) -> EscapeDebug {
|
2014-10-31 16:20:41 -07:00
|
|
|
let init_state = match self {
|
2014-12-15 08:49:01 -08:00
|
|
|
'\t' => EscapeDefaultState::Backslash('t'),
|
|
|
|
'\r' => EscapeDefaultState::Backslash('r'),
|
|
|
|
'\n' => EscapeDefaultState::Backslash('n'),
|
2015-09-29 21:25:40 +03:00
|
|
|
'\\' | '\'' | '"' => EscapeDefaultState::Backslash(self),
|
Escape fewer Unicode codepoints in `Debug` impl of `str`
Use the same procedure as Python to determine whether a character is
printable, described in [PEP 3138]. In particular, this means that the
following character classes are escaped:
- Cc (Other, Control)
- Cf (Other, Format)
- Cs (Other, Surrogate), even though they can't appear in Rust strings
- Co (Other, Private Use)
- Cn (Other, Not Assigned)
- Zl (Separator, Line)
- Zp (Separator, Paragraph)
- Zs (Separator, Space), except for the ASCII space `' '` (`0x20`)
This allows for user-friendly inspection of strings that are not
English (e.g. compare `"\u{e9}\u{e8}\u{ea}"` to `"éèê"`).
Fixes #34318.
[PEP 3138]: https://www.python.org/dev/peps/pep-3138/
2016-06-26 15:11:48 +02:00
|
|
|
c if is_printable(c) => EscapeDefaultState::Char(c),
|
|
|
|
c => EscapeDefaultState::Unicode(c.escape_unicode()),
|
2014-10-31 16:20:41 -07:00
|
|
|
};
|
2016-07-27 12:10:31 +02:00
|
|
|
EscapeDebug(EscapeDefault { state: init_state })
|
2014-10-13 13:03:42 -07:00
|
|
|
}
|
2013-05-19 05:50:02 +10:00
|
|
|
|
2014-10-08 17:33:02 -07:00
|
|
|
#[inline]
|
2015-02-15 00:09:40 +03:00
|
|
|
fn len_utf8(self) -> usize {
|
2014-10-14 13:08:54 -07:00
|
|
|
let code = self as u32;
|
2015-01-27 14:09:18 +01:00
|
|
|
if code < MAX_ONE_B {
|
|
|
|
1
|
|
|
|
} else if code < MAX_TWO_B {
|
|
|
|
2
|
|
|
|
} else if code < MAX_THREE_B {
|
|
|
|
3
|
|
|
|
} else {
|
|
|
|
4
|
2014-10-13 13:03:42 -07:00
|
|
|
}
|
|
|
|
}
|
2014-10-08 17:33:02 -07:00
|
|
|
|
2014-10-08 17:40:31 -07:00
|
|
|
#[inline]
|
2015-02-15 00:09:40 +03:00
|
|
|
fn len_utf16(self) -> usize {
|
2014-10-14 13:08:54 -07:00
|
|
|
let ch = self as u32;
|
2015-03-03 10:42:26 +02:00
|
|
|
if (ch & 0xFFFF) == ch { 1 } else { 2 }
|
2014-10-08 17:40:31 -07:00
|
|
|
}
|
|
|
|
|
2014-08-14 01:02:31 +02:00
|
|
|
#[inline]
|
2016-09-08 13:54:39 +02:00
|
|
|
fn encode_utf8(self, dst: &mut [u8]) -> &mut str {
|
2016-03-11 11:01:46 -08:00
|
|
|
let code = self as u32;
|
2016-09-08 13:54:39 +02:00
|
|
|
unsafe {
|
|
|
|
let len =
|
|
|
|
if code < MAX_ONE_B && !dst.is_empty() {
|
|
|
|
*dst.get_unchecked_mut(0) = code as u8;
|
|
|
|
1
|
|
|
|
} else if code < MAX_TWO_B && dst.len() >= 2 {
|
|
|
|
*dst.get_unchecked_mut(0) = (code >> 6 & 0x1F) as u8 | TAG_TWO_B;
|
|
|
|
*dst.get_unchecked_mut(1) = (code & 0x3F) as u8 | TAG_CONT;
|
|
|
|
2
|
|
|
|
} else if code < MAX_THREE_B && dst.len() >= 3 {
|
|
|
|
*dst.get_unchecked_mut(0) = (code >> 12 & 0x0F) as u8 | TAG_THREE_B;
|
|
|
|
*dst.get_unchecked_mut(1) = (code >> 6 & 0x3F) as u8 | TAG_CONT;
|
|
|
|
*dst.get_unchecked_mut(2) = (code & 0x3F) as u8 | TAG_CONT;
|
|
|
|
3
|
|
|
|
} else if dst.len() >= 4 {
|
|
|
|
*dst.get_unchecked_mut(0) = (code >> 18 & 0x07) as u8 | TAG_FOUR_B;
|
|
|
|
*dst.get_unchecked_mut(1) = (code >> 12 & 0x3F) as u8 | TAG_CONT;
|
|
|
|
*dst.get_unchecked_mut(2) = (code >> 6 & 0x3F) as u8 | TAG_CONT;
|
|
|
|
*dst.get_unchecked_mut(3) = (code & 0x3F) as u8 | TAG_CONT;
|
|
|
|
4
|
|
|
|
} else {
|
|
|
|
panic!("encode_utf8: need {} bytes to encode U+{:X}, but the buffer has {}",
|
|
|
|
from_u32_unchecked(code).len_utf8(),
|
|
|
|
code,
|
|
|
|
dst.len())
|
|
|
|
};
|
2017-03-10 12:10:26 -05:00
|
|
|
from_utf8_unchecked_mut(dst.get_unchecked_mut(..len))
|
2016-09-08 13:54:39 +02:00
|
|
|
}
|
2013-08-10 00:28:47 -07:00
|
|
|
}
|
2014-04-11 12:49:31 -07:00
|
|
|
|
2014-08-14 01:02:31 +02:00
|
|
|
#[inline]
|
2016-09-08 13:54:39 +02:00
|
|
|
fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] {
|
2016-03-11 11:01:46 -08:00
|
|
|
let mut code = self as u32;
|
2016-09-08 13:54:39 +02:00
|
|
|
unsafe {
|
|
|
|
if (code & 0xFFFF) == code && !dst.is_empty() {
|
|
|
|
// The BMP falls through (assuming non-surrogate, as it should)
|
|
|
|
*dst.get_unchecked_mut(0) = code as u16;
|
|
|
|
slice::from_raw_parts_mut(dst.as_mut_ptr(), 1)
|
|
|
|
} else if dst.len() >= 2 {
|
|
|
|
// Supplementary planes break into surrogates.
|
|
|
|
code -= 0x1_0000;
|
|
|
|
*dst.get_unchecked_mut(0) = 0xD800 | ((code >> 10) as u16);
|
|
|
|
*dst.get_unchecked_mut(1) = 0xDC00 | ((code as u16) & 0x3FF);
|
|
|
|
slice::from_raw_parts_mut(dst.as_mut_ptr(), 2)
|
|
|
|
} else {
|
|
|
|
panic!("encode_utf16: need {} units to encode U+{:X}, but the buffer has {}",
|
|
|
|
from_u32_unchecked(code).len_utf16(),
|
|
|
|
code,
|
|
|
|
dst.len())
|
|
|
|
}
|
|
|
|
}
|
2014-04-11 12:49:31 -07:00
|
|
|
}
|
2013-05-19 05:50:02 +10:00
|
|
|
}
|
2014-10-31 16:20:41 -07:00
|
|
|
|
2015-11-24 11:49:19 -05:00
|
|
|
/// Returns an iterator that yields the hexadecimal Unicode escape of a
|
|
|
|
/// character, as `char`s.
|
|
|
|
///
|
2017-03-12 14:04:52 -04:00
|
|
|
/// This `struct` is created by the [`escape_unicode`] method on [`char`]. See
|
2015-11-24 11:49:19 -05:00
|
|
|
/// its documentation for more.
|
|
|
|
///
|
2017-03-12 14:04:52 -04:00
|
|
|
/// [`escape_unicode`]: ../../std/primitive.char.html#method.escape_unicode
|
2016-03-07 23:55:52 -08:00
|
|
|
/// [`char`]: ../../std/primitive.char.html
|
2016-03-04 18:49:43 -08:00
|
|
|
#[derive(Clone, Debug)]
|
2015-01-23 21:48:20 -08:00
|
|
|
#[stable(feature = "rust1", since = "1.0.0")]
|
2014-12-15 08:49:01 -08:00
|
|
|
pub struct EscapeUnicode {
|
2014-10-31 16:20:41 -07:00
|
|
|
c: char,
|
2015-12-30 21:45:24 +01:00
|
|
|
state: EscapeUnicodeState,
|
2016-01-28 15:12:16 +01:00
|
|
|
|
|
|
|
// The index of the next hex digit to be printed (0 if none),
|
|
|
|
// i.e. the number of remaining hex digits to be printed;
|
|
|
|
// increasing from the least significant digit: 0x543210
|
|
|
|
hex_digit_idx: usize,
|
2014-10-31 16:20:41 -07:00
|
|
|
}
|
|
|
|
|
2016-05-26 10:04:05 +02:00
|
|
|
// The enum values are ordered so that their representation is the
|
|
|
|
// same as the remaining length (besides the hexadecimal digits). This
|
|
|
|
// likely makes `len()` a single load from memory) and inline-worth.
|
2016-03-04 18:49:43 -08:00
|
|
|
#[derive(Clone, Debug)]
|
2014-12-15 08:49:01 -08:00
|
|
|
enum EscapeUnicodeState {
|
|
|
|
Done,
|
2016-01-18 17:36:12 +01:00
|
|
|
RightBrace,
|
|
|
|
Value,
|
|
|
|
LeftBrace,
|
|
|
|
Type,
|
|
|
|
Backslash,
|
2014-10-31 16:20:41 -07:00
|
|
|
}
|
|
|
|
|
2015-01-23 21:48:20 -08:00
|
|
|
#[stable(feature = "rust1", since = "1.0.0")]
|
2014-12-29 16:18:41 -05:00
|
|
|
impl Iterator for EscapeUnicode {
|
|
|
|
type Item = char;
|
|
|
|
|
2014-10-31 16:20:41 -07:00
|
|
|
fn next(&mut self) -> Option<char> {
|
|
|
|
match self.state {
|
2014-12-15 08:49:01 -08:00
|
|
|
EscapeUnicodeState::Backslash => {
|
|
|
|
self.state = EscapeUnicodeState::Type;
|
2014-10-31 16:20:41 -07:00
|
|
|
Some('\\')
|
|
|
|
}
|
2014-12-15 08:49:01 -08:00
|
|
|
EscapeUnicodeState::Type => {
|
|
|
|
self.state = EscapeUnicodeState::LeftBrace;
|
|
|
|
Some('u')
|
2014-10-31 16:20:41 -07:00
|
|
|
}
|
2014-12-15 08:49:01 -08:00
|
|
|
EscapeUnicodeState::LeftBrace => {
|
2015-12-30 21:45:24 +01:00
|
|
|
self.state = EscapeUnicodeState::Value;
|
2014-12-15 08:49:01 -08:00
|
|
|
Some('{')
|
|
|
|
}
|
2015-12-30 21:45:24 +01:00
|
|
|
EscapeUnicodeState::Value => {
|
2016-01-28 15:18:42 +01:00
|
|
|
let hex_digit = ((self.c as u32) >> (self.hex_digit_idx * 4)) & 0xf;
|
|
|
|
let c = from_digit(hex_digit, 16).unwrap();
|
2016-01-28 15:12:16 +01:00
|
|
|
if self.hex_digit_idx == 0 {
|
2014-12-15 08:49:01 -08:00
|
|
|
self.state = EscapeUnicodeState::RightBrace;
|
|
|
|
} else {
|
2016-01-28 15:12:16 +01:00
|
|
|
self.hex_digit_idx -= 1;
|
2014-12-15 08:49:01 -08:00
|
|
|
}
|
2015-07-23 12:24:27 +02:00
|
|
|
Some(c)
|
2014-12-15 08:49:01 -08:00
|
|
|
}
|
|
|
|
EscapeUnicodeState::RightBrace => {
|
|
|
|
self.state = EscapeUnicodeState::Done;
|
|
|
|
Some('}')
|
2014-10-31 16:20:41 -07:00
|
|
|
}
|
2014-12-15 08:49:01 -08:00
|
|
|
EscapeUnicodeState::Done => None,
|
2014-10-31 16:20:41 -07:00
|
|
|
}
|
|
|
|
}
|
2015-09-30 20:31:41 +03:00
|
|
|
|
2016-01-18 17:36:12 +01:00
|
|
|
#[inline]
|
2015-09-30 20:31:41 +03:00
|
|
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
2016-01-18 17:36:12 +01:00
|
|
|
let n = self.len();
|
2015-09-30 20:31:41 +03:00
|
|
|
(n, Some(n))
|
|
|
|
}
|
2016-01-18 17:46:53 +01:00
|
|
|
|
2015-12-30 16:42:52 +01:00
|
|
|
#[inline]
|
|
|
|
fn count(self) -> usize {
|
|
|
|
self.len()
|
|
|
|
}
|
|
|
|
|
2016-01-18 17:46:53 +01:00
|
|
|
fn last(self) -> Option<char> {
|
|
|
|
match self.state {
|
|
|
|
EscapeUnicodeState::Done => None,
|
|
|
|
|
|
|
|
EscapeUnicodeState::RightBrace |
|
|
|
|
EscapeUnicodeState::Value |
|
|
|
|
EscapeUnicodeState::LeftBrace |
|
|
|
|
EscapeUnicodeState::Type |
|
|
|
|
EscapeUnicodeState::Backslash => Some('}'),
|
|
|
|
}
|
|
|
|
}
|
2014-10-31 16:20:41 -07:00
|
|
|
}
|
|
|
|
|
2015-12-30 10:08:28 +01:00
|
|
|
#[stable(feature = "exact_size_escape", since = "1.11.0")]
|
2016-01-18 17:36:12 +01:00
|
|
|
impl ExactSizeIterator for EscapeUnicode {
|
|
|
|
#[inline]
|
|
|
|
fn len(&self) -> usize {
|
|
|
|
// The match is a single memory access with no branching
|
|
|
|
self.hex_digit_idx + match self.state {
|
|
|
|
EscapeUnicodeState::Done => 0,
|
|
|
|
EscapeUnicodeState::RightBrace => 1,
|
|
|
|
EscapeUnicodeState::Value => 2,
|
|
|
|
EscapeUnicodeState::LeftBrace => 3,
|
|
|
|
EscapeUnicodeState::Type => 4,
|
|
|
|
EscapeUnicodeState::Backslash => 5,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-12-30 10:08:28 +01:00
|
|
|
|
2016-08-13 14:42:36 -04:00
|
|
|
#[unstable(feature = "fused", issue = "35602")]
|
|
|
|
impl FusedIterator for EscapeUnicode {}
|
|
|
|
|
2017-01-29 13:31:47 +00:00
|
|
|
#[stable(feature = "char_struct_display", since = "1.16.0")]
|
2017-01-07 13:16:03 -05:00
|
|
|
impl fmt::Display for EscapeUnicode {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
for c in self.clone() {
|
|
|
|
f.write_char(c)?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-24 11:49:19 -05:00
|
|
|
/// An iterator that yields the literal escape code of a `char`.
|
|
|
|
///
|
2017-03-12 14:04:52 -04:00
|
|
|
/// This `struct` is created by the [`escape_default`] method on [`char`]. See
|
2015-11-24 11:49:19 -05:00
|
|
|
/// its documentation for more.
|
|
|
|
///
|
2017-03-12 14:04:52 -04:00
|
|
|
/// [`escape_default`]: ../../std/primitive.char.html#method.escape_default
|
2016-03-07 23:55:52 -08:00
|
|
|
/// [`char`]: ../../std/primitive.char.html
|
2016-03-04 18:49:43 -08:00
|
|
|
#[derive(Clone, Debug)]
|
2015-01-23 21:48:20 -08:00
|
|
|
#[stable(feature = "rust1", since = "1.0.0")]
|
2014-12-15 08:49:01 -08:00
|
|
|
pub struct EscapeDefault {
|
|
|
|
state: EscapeDefaultState
|
2014-10-31 16:20:41 -07:00
|
|
|
}
|
|
|
|
|
2016-03-04 18:49:43 -08:00
|
|
|
#[derive(Clone, Debug)]
|
2014-12-15 08:49:01 -08:00
|
|
|
enum EscapeDefaultState {
|
2014-10-31 16:20:41 -07:00
|
|
|
Done,
|
2016-01-18 17:36:12 +01:00
|
|
|
Char(char),
|
|
|
|
Backslash(char),
|
2014-12-15 08:49:01 -08:00
|
|
|
Unicode(EscapeUnicode),
|
2014-10-31 16:20:41 -07:00
|
|
|
}
|
|
|
|
|
2015-01-23 21:48:20 -08:00
|
|
|
#[stable(feature = "rust1", since = "1.0.0")]
|
2014-12-29 16:18:41 -05:00
|
|
|
impl Iterator for EscapeDefault {
|
|
|
|
type Item = char;
|
|
|
|
|
2014-10-31 16:20:41 -07:00
|
|
|
fn next(&mut self) -> Option<char> {
|
|
|
|
match self.state {
|
2014-12-15 08:49:01 -08:00
|
|
|
EscapeDefaultState::Backslash(c) => {
|
|
|
|
self.state = EscapeDefaultState::Char(c);
|
2014-10-31 16:20:41 -07:00
|
|
|
Some('\\')
|
|
|
|
}
|
2014-12-15 08:49:01 -08:00
|
|
|
EscapeDefaultState::Char(c) => {
|
|
|
|
self.state = EscapeDefaultState::Done;
|
2014-10-31 16:20:41 -07:00
|
|
|
Some(c)
|
|
|
|
}
|
2014-12-15 08:49:01 -08:00
|
|
|
EscapeDefaultState::Done => None,
|
2015-09-30 20:31:41 +03:00
|
|
|
EscapeDefaultState::Unicode(ref mut iter) => iter.next(),
|
2014-10-31 16:20:41 -07:00
|
|
|
}
|
|
|
|
}
|
2015-09-29 21:25:40 +03:00
|
|
|
|
2016-01-18 17:36:12 +01:00
|
|
|
#[inline]
|
2015-09-29 21:25:40 +03:00
|
|
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
2016-01-18 17:36:12 +01:00
|
|
|
let n = self.len();
|
|
|
|
(n, Some(n))
|
2015-09-29 21:25:40 +03:00
|
|
|
}
|
2015-12-22 10:39:59 +01:00
|
|
|
|
2015-12-30 16:42:52 +01:00
|
|
|
#[inline]
|
2015-12-22 10:39:59 +01:00
|
|
|
fn count(self) -> usize {
|
2015-12-30 16:42:52 +01:00
|
|
|
self.len()
|
2015-12-22 10:39:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
fn nth(&mut self, n: usize) -> Option<char> {
|
2016-01-12 14:35:04 +01:00
|
|
|
match self.state {
|
|
|
|
EscapeDefaultState::Backslash(c) if n == 0 => {
|
|
|
|
self.state = EscapeDefaultState::Char(c);
|
|
|
|
Some('\\')
|
|
|
|
},
|
|
|
|
EscapeDefaultState::Backslash(c) if n == 1 => {
|
|
|
|
self.state = EscapeDefaultState::Done;
|
|
|
|
Some(c)
|
|
|
|
},
|
|
|
|
EscapeDefaultState::Backslash(_) => {
|
|
|
|
self.state = EscapeDefaultState::Done;
|
|
|
|
None
|
|
|
|
},
|
|
|
|
EscapeDefaultState::Char(c) => {
|
|
|
|
self.state = EscapeDefaultState::Done;
|
2015-12-22 10:39:59 +01:00
|
|
|
|
2016-01-12 14:35:04 +01:00
|
|
|
if n == 0 {
|
|
|
|
Some(c)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
},
|
|
|
|
EscapeDefaultState::Done => return None,
|
|
|
|
EscapeDefaultState::Unicode(ref mut i) => return i.nth(n),
|
2015-12-22 10:39:59 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn last(self) -> Option<char> {
|
|
|
|
match self.state {
|
2016-01-12 14:35:04 +01:00
|
|
|
EscapeDefaultState::Unicode(iter) => iter.last(),
|
|
|
|
EscapeDefaultState::Done => None,
|
2015-12-22 10:39:59 +01:00
|
|
|
EscapeDefaultState::Backslash(c) | EscapeDefaultState::Char(c) => Some(c),
|
|
|
|
}
|
|
|
|
}
|
2014-10-31 16:20:41 -07:00
|
|
|
}
|
2016-03-11 11:01:46 -08:00
|
|
|
|
2015-12-30 10:08:28 +01:00
|
|
|
#[stable(feature = "exact_size_escape", since = "1.11.0")]
|
2016-01-18 17:36:12 +01:00
|
|
|
impl ExactSizeIterator for EscapeDefault {
|
|
|
|
fn len(&self) -> usize {
|
|
|
|
match self.state {
|
|
|
|
EscapeDefaultState::Done => 0,
|
|
|
|
EscapeDefaultState::Char(_) => 1,
|
|
|
|
EscapeDefaultState::Backslash(_) => 2,
|
|
|
|
EscapeDefaultState::Unicode(ref iter) => iter.len(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-12-30 10:08:28 +01:00
|
|
|
|
2016-08-13 14:42:36 -04:00
|
|
|
#[unstable(feature = "fused", issue = "35602")]
|
|
|
|
impl FusedIterator for EscapeDefault {}
|
|
|
|
|
2017-01-29 13:31:47 +00:00
|
|
|
#[stable(feature = "char_struct_display", since = "1.16.0")]
|
2017-01-07 13:16:03 -05:00
|
|
|
impl fmt::Display for EscapeDefault {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
for c in self.clone() {
|
|
|
|
f.write_char(c)?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-26 01:39:54 +02:00
|
|
|
/// An iterator that yields the literal escape code of a `char`.
|
|
|
|
///
|
2017-03-12 14:04:52 -04:00
|
|
|
/// This `struct` is created by the [`escape_debug`] method on [`char`]. See its
|
2016-07-26 01:39:54 +02:00
|
|
|
/// documentation for more.
|
|
|
|
///
|
2017-03-12 14:04:52 -04:00
|
|
|
/// [`escape_debug`]: ../../std/primitive.char.html#method.escape_debug
|
2016-07-26 01:39:54 +02:00
|
|
|
/// [`char`]: ../../std/primitive.char.html
|
2017-07-20 15:38:59 -07:00
|
|
|
#[stable(feature = "char_escape_debug", since = "1.20.0")]
|
2016-07-26 01:39:54 +02:00
|
|
|
#[derive(Clone, Debug)]
|
2016-07-27 12:10:31 +02:00
|
|
|
pub struct EscapeDebug(EscapeDefault);
|
2016-07-26 01:39:54 +02:00
|
|
|
|
2017-07-20 15:38:59 -07:00
|
|
|
#[stable(feature = "char_escape_debug", since = "1.20.0")]
|
2016-07-27 12:10:31 +02:00
|
|
|
impl Iterator for EscapeDebug {
|
2016-07-26 01:39:54 +02:00
|
|
|
type Item = char;
|
|
|
|
fn next(&mut self) -> Option<char> { self.0.next() }
|
|
|
|
fn size_hint(&self) -> (usize, Option<usize>) { self.0.size_hint() }
|
|
|
|
}
|
|
|
|
|
2017-07-20 15:38:59 -07:00
|
|
|
#[stable(feature = "char_escape_debug", since = "1.20.0")]
|
2016-07-27 12:10:31 +02:00
|
|
|
impl ExactSizeIterator for EscapeDebug { }
|
2016-07-26 01:39:54 +02:00
|
|
|
|
2016-08-13 14:42:36 -04:00
|
|
|
#[unstable(feature = "fused", issue = "35602")]
|
|
|
|
impl FusedIterator for EscapeDebug {}
|
|
|
|
|
2017-07-20 15:38:59 -07:00
|
|
|
#[stable(feature = "char_escape_debug", since = "1.20.0")]
|
2017-01-07 13:16:03 -05:00
|
|
|
impl fmt::Display for EscapeDebug {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
fmt::Display::fmt(&self.0, f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-27 08:16:27 -08:00
|
|
|
|
|
|
|
|
|
|
|
/// An iterator over an iterator of bytes of the characters the bytes represent
|
|
|
|
/// as UTF-8
|
|
|
|
#[unstable(feature = "decode_utf8", issue = "33906")]
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct DecodeUtf8<I: Iterator<Item = u8>>(::iter::Peekable<I>);
|
|
|
|
|
|
|
|
/// Decodes an `Iterator` of bytes as UTF-8.
|
|
|
|
#[unstable(feature = "decode_utf8", issue = "33906")]
|
|
|
|
#[inline]
|
|
|
|
pub fn decode_utf8<I: IntoIterator<Item = u8>>(i: I) -> DecodeUtf8<I::IntoIter> {
|
|
|
|
DecodeUtf8(i.into_iter().peekable())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// `<DecodeUtf8 as Iterator>::next` returns this for an invalid input sequence.
|
|
|
|
#[unstable(feature = "decode_utf8", issue = "33906")]
|
2016-09-12 21:37:41 +02:00
|
|
|
#[derive(PartialEq, Eq, Debug)]
|
2016-05-27 08:16:27 -08:00
|
|
|
pub struct InvalidSequence(());
|
|
|
|
|
|
|
|
#[unstable(feature = "decode_utf8", issue = "33906")]
|
|
|
|
impl<I: Iterator<Item = u8>> Iterator for DecodeUtf8<I> {
|
|
|
|
type Item = Result<char, InvalidSequence>;
|
|
|
|
#[inline]
|
2016-08-23 22:09:59 +02:00
|
|
|
|
2016-05-27 08:16:27 -08:00
|
|
|
fn next(&mut self) -> Option<Result<char, InvalidSequence>> {
|
2016-08-23 22:09:59 +02:00
|
|
|
self.0.next().map(|first_byte| {
|
|
|
|
// Emit InvalidSequence according to
|
|
|
|
// Unicode §5.22 Best Practice for U+FFFD Substitution
|
|
|
|
// http://www.unicode.org/versions/Unicode9.0.0/ch05.pdf#G40630
|
|
|
|
|
|
|
|
// Roughly: consume at least one byte,
|
|
|
|
// then validate one byte at a time and stop before the first unexpected byte
|
|
|
|
// (which might be the valid start of the next byte sequence).
|
|
|
|
|
|
|
|
let mut code_point;
|
|
|
|
macro_rules! first_byte {
|
|
|
|
($mask: expr) => {
|
|
|
|
code_point = u32::from(first_byte & $mask)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
macro_rules! continuation_byte {
|
|
|
|
() => { continuation_byte!(0x80...0xBF) };
|
|
|
|
($range: pat) => {
|
2016-05-27 08:16:27 -08:00
|
|
|
match self.0.peek() {
|
2016-08-23 22:09:59 +02:00
|
|
|
Some(&byte @ $range) => {
|
|
|
|
code_point = (code_point << 6) | u32::from(byte & 0b0011_1111);
|
2016-05-27 08:16:27 -08:00
|
|
|
self.0.next();
|
2016-08-23 22:09:59 +02:00
|
|
|
}
|
|
|
|
_ => return Err(InvalidSequence(()))
|
2016-05-27 08:16:27 -08:00
|
|
|
}
|
|
|
|
}
|
2016-08-23 22:09:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
match first_byte {
|
|
|
|
0x00...0x7F => {
|
|
|
|
first_byte!(0b1111_1111);
|
|
|
|
}
|
|
|
|
0xC2...0xDF => {
|
|
|
|
first_byte!(0b0001_1111);
|
|
|
|
continuation_byte!();
|
|
|
|
}
|
|
|
|
0xE0 => {
|
|
|
|
first_byte!(0b0000_1111);
|
|
|
|
continuation_byte!(0xA0...0xBF); // 0x80...0x9F here are overlong
|
|
|
|
continuation_byte!();
|
2016-05-27 08:16:27 -08:00
|
|
|
}
|
2016-08-23 22:09:59 +02:00
|
|
|
0xE1...0xEC | 0xEE...0xEF => {
|
|
|
|
first_byte!(0b0000_1111);
|
|
|
|
continuation_byte!();
|
|
|
|
continuation_byte!();
|
|
|
|
}
|
|
|
|
0xED => {
|
|
|
|
first_byte!(0b0000_1111);
|
|
|
|
continuation_byte!(0x80...0x9F); // 0xA0..0xBF here are surrogates
|
|
|
|
continuation_byte!();
|
|
|
|
}
|
|
|
|
0xF0 => {
|
|
|
|
first_byte!(0b0000_0111);
|
|
|
|
continuation_byte!(0x90...0xBF); // 0x80..0x8F here are overlong
|
|
|
|
continuation_byte!();
|
|
|
|
continuation_byte!();
|
|
|
|
}
|
|
|
|
0xF1...0xF3 => {
|
|
|
|
first_byte!(0b0000_0111);
|
|
|
|
continuation_byte!();
|
|
|
|
continuation_byte!();
|
|
|
|
continuation_byte!();
|
|
|
|
}
|
|
|
|
0xF4 => {
|
|
|
|
first_byte!(0b0000_0111);
|
|
|
|
continuation_byte!(0x80...0x8F); // 0x90..0xBF here are beyond char::MAX
|
|
|
|
continuation_byte!();
|
|
|
|
continuation_byte!();
|
|
|
|
}
|
|
|
|
_ => return Err(InvalidSequence(())) // Illegal first byte, overlong, or beyond MAX
|
|
|
|
}
|
|
|
|
unsafe {
|
|
|
|
Ok(from_u32_unchecked(code_point))
|
2016-05-27 08:16:27 -08:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2016-08-13 14:42:36 -04:00
|
|
|
|
|
|
|
#[unstable(feature = "fused", issue = "35602")]
|
|
|
|
impl<I: FusedIterator<Item = u8>> FusedIterator for DecodeUtf8<I> {}
|