1229 lines
42 KiB
Rust
1229 lines
42 KiB
Rust
//! This uses the name `AsciiChar`, even though it's not exposed that way right now,
|
|
//! because it avoids a whole bunch of "are you sure you didn't mean `char`?"
|
|
//! suggestions from rustc if you get anything slightly wrong in here, and overall
|
|
//! helps with clarity as we're also referring to `char` intentionally in here.
|
|
|
|
use crate::mem::transmute;
|
|
use crate::{assert_unsafe_precondition, fmt};
|
|
|
|
/// One of the 128 Unicode characters from U+0000 through U+007F,
|
|
/// often known as the [ASCII] subset.
|
|
///
|
|
/// Officially, this is the first [block] in Unicode, _Basic Latin_.
|
|
/// For details, see the [*C0 Controls and Basic Latin*][chart] code chart.
|
|
///
|
|
/// This block was based on older 7-bit character code standards such as
|
|
/// ANSI X3.4-1977, ISO 646-1973, and [NIST FIPS 1-2].
|
|
///
|
|
/// # When to use this
|
|
///
|
|
/// The main advantage of this subset is that it's always valid UTF-8. As such,
|
|
/// the `&[ascii::Char]` -> `&str` conversion function (as well as other related
|
|
/// ones) are O(1): *no* runtime checks are needed.
|
|
///
|
|
/// If you're consuming strings, you should usually handle Unicode and thus
|
|
/// accept `str`s, not limit yourself to `ascii::Char`s.
|
|
///
|
|
/// However, certain formats are intentionally designed to produce ASCII-only
|
|
/// output in order to be 8-bit-clean. In those cases, it can be simpler and
|
|
/// faster to generate `ascii::Char`s instead of dealing with the variable width
|
|
/// properties of general UTF-8 encoded strings, while still allowing the result
|
|
/// to be used freely with other Rust things that deal in general `str`s.
|
|
///
|
|
/// For example, a UUID library might offer a way to produce the string
|
|
/// representation of a UUID as an `[ascii::Char; 36]` to avoid memory
|
|
/// allocation yet still allow it to be used as UTF-8 via `as_str` without
|
|
/// paying for validation (or needing `unsafe` code) the way it would if it
|
|
/// were provided as a `[u8; 36]`.
|
|
///
|
|
/// # Layout
|
|
///
|
|
/// This type is guaranteed to have a size and alignment of 1 byte.
|
|
///
|
|
/// # Names
|
|
///
|
|
/// The variants on this type are [Unicode names][NamesList] of the characters
|
|
/// in upper camel case, with a few tweaks:
|
|
/// - For `<control>` characters, the primary alias name is used.
|
|
/// - `LATIN` is dropped, as this block has no non-latin letters.
|
|
/// - `LETTER` is dropped, as `CAPITAL`/`SMALL` suffices in this block.
|
|
/// - `DIGIT`s use a single digit rather than writing out `ZERO`, `ONE`, etc.
|
|
///
|
|
/// [ASCII]: https://www.unicode.org/glossary/index.html#ASCII
|
|
/// [block]: https://www.unicode.org/glossary/index.html#block
|
|
/// [chart]: https://www.unicode.org/charts/PDF/U0000.pdf
|
|
/// [NIST FIPS 1-2]: https://nvlpubs.nist.gov/nistpubs/Legacy/FIPS/fipspub1-2-1977.pdf
|
|
/// [NamesList]: https://www.unicode.org/Public/15.0.0/ucd/NamesList.txt
|
|
#[derive(Copy, Hash)]
|
|
#[derive_const(Clone, Eq, PartialEq, Ord, PartialOrd)]
|
|
#[unstable(feature = "ascii_char", issue = "110998")]
|
|
#[repr(u8)]
|
|
pub enum AsciiChar {
|
|
/// U+0000 (The default variant)
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
Null = 0,
|
|
/// U+0001
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
StartOfHeading = 1,
|
|
/// U+0002
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
StartOfText = 2,
|
|
/// U+0003
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
EndOfText = 3,
|
|
/// U+0004
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
EndOfTransmission = 4,
|
|
/// U+0005
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
Enquiry = 5,
|
|
/// U+0006
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
Acknowledge = 6,
|
|
/// U+0007
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
Bell = 7,
|
|
/// U+0008
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
Backspace = 8,
|
|
/// U+0009
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
CharacterTabulation = 9,
|
|
/// U+000A
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
LineFeed = 10,
|
|
/// U+000B
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
LineTabulation = 11,
|
|
/// U+000C
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
FormFeed = 12,
|
|
/// U+000D
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
CarriageReturn = 13,
|
|
/// U+000E
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
ShiftOut = 14,
|
|
/// U+000F
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
ShiftIn = 15,
|
|
/// U+0010
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
DataLinkEscape = 16,
|
|
/// U+0011
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
DeviceControlOne = 17,
|
|
/// U+0012
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
DeviceControlTwo = 18,
|
|
/// U+0013
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
DeviceControlThree = 19,
|
|
/// U+0014
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
DeviceControlFour = 20,
|
|
/// U+0015
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
NegativeAcknowledge = 21,
|
|
/// U+0016
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
SynchronousIdle = 22,
|
|
/// U+0017
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
EndOfTransmissionBlock = 23,
|
|
/// U+0018
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
Cancel = 24,
|
|
/// U+0019
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
EndOfMedium = 25,
|
|
/// U+001A
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
Substitute = 26,
|
|
/// U+001B
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
Escape = 27,
|
|
/// U+001C
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
InformationSeparatorFour = 28,
|
|
/// U+001D
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
InformationSeparatorThree = 29,
|
|
/// U+001E
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
InformationSeparatorTwo = 30,
|
|
/// U+001F
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
InformationSeparatorOne = 31,
|
|
/// U+0020
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
Space = 32,
|
|
/// U+0021
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
ExclamationMark = 33,
|
|
/// U+0022
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
QuotationMark = 34,
|
|
/// U+0023
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
NumberSign = 35,
|
|
/// U+0024
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
DollarSign = 36,
|
|
/// U+0025
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
PercentSign = 37,
|
|
/// U+0026
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
Ampersand = 38,
|
|
/// U+0027
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
Apostrophe = 39,
|
|
/// U+0028
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
LeftParenthesis = 40,
|
|
/// U+0029
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
RightParenthesis = 41,
|
|
/// U+002A
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
Asterisk = 42,
|
|
/// U+002B
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
PlusSign = 43,
|
|
/// U+002C
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
Comma = 44,
|
|
/// U+002D
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
HyphenMinus = 45,
|
|
/// U+002E
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
FullStop = 46,
|
|
/// U+002F
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
Solidus = 47,
|
|
/// U+0030
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
Digit0 = 48,
|
|
/// U+0031
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
Digit1 = 49,
|
|
/// U+0032
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
Digit2 = 50,
|
|
/// U+0033
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
Digit3 = 51,
|
|
/// U+0034
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
Digit4 = 52,
|
|
/// U+0035
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
Digit5 = 53,
|
|
/// U+0036
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
Digit6 = 54,
|
|
/// U+0037
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
Digit7 = 55,
|
|
/// U+0038
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
Digit8 = 56,
|
|
/// U+0039
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
Digit9 = 57,
|
|
/// U+003A
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
Colon = 58,
|
|
/// U+003B
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
Semicolon = 59,
|
|
/// U+003C
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
LessThanSign = 60,
|
|
/// U+003D
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
EqualsSign = 61,
|
|
/// U+003E
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
GreaterThanSign = 62,
|
|
/// U+003F
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
QuestionMark = 63,
|
|
/// U+0040
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
CommercialAt = 64,
|
|
/// U+0041
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
CapitalA = 65,
|
|
/// U+0042
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
CapitalB = 66,
|
|
/// U+0043
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
CapitalC = 67,
|
|
/// U+0044
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
CapitalD = 68,
|
|
/// U+0045
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
CapitalE = 69,
|
|
/// U+0046
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
CapitalF = 70,
|
|
/// U+0047
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
CapitalG = 71,
|
|
/// U+0048
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
CapitalH = 72,
|
|
/// U+0049
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
CapitalI = 73,
|
|
/// U+004A
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
CapitalJ = 74,
|
|
/// U+004B
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
CapitalK = 75,
|
|
/// U+004C
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
CapitalL = 76,
|
|
/// U+004D
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
CapitalM = 77,
|
|
/// U+004E
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
CapitalN = 78,
|
|
/// U+004F
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
CapitalO = 79,
|
|
/// U+0050
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
CapitalP = 80,
|
|
/// U+0051
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
CapitalQ = 81,
|
|
/// U+0052
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
CapitalR = 82,
|
|
/// U+0053
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
CapitalS = 83,
|
|
/// U+0054
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
CapitalT = 84,
|
|
/// U+0055
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
CapitalU = 85,
|
|
/// U+0056
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
CapitalV = 86,
|
|
/// U+0057
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
CapitalW = 87,
|
|
/// U+0058
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
CapitalX = 88,
|
|
/// U+0059
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
CapitalY = 89,
|
|
/// U+005A
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
CapitalZ = 90,
|
|
/// U+005B
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
LeftSquareBracket = 91,
|
|
/// U+005C
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
ReverseSolidus = 92,
|
|
/// U+005D
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
RightSquareBracket = 93,
|
|
/// U+005E
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
CircumflexAccent = 94,
|
|
/// U+005F
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
LowLine = 95,
|
|
/// U+0060
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
GraveAccent = 96,
|
|
/// U+0061
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
SmallA = 97,
|
|
/// U+0062
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
SmallB = 98,
|
|
/// U+0063
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
SmallC = 99,
|
|
/// U+0064
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
SmallD = 100,
|
|
/// U+0065
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
SmallE = 101,
|
|
/// U+0066
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
SmallF = 102,
|
|
/// U+0067
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
SmallG = 103,
|
|
/// U+0068
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
SmallH = 104,
|
|
/// U+0069
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
SmallI = 105,
|
|
/// U+006A
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
SmallJ = 106,
|
|
/// U+006B
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
SmallK = 107,
|
|
/// U+006C
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
SmallL = 108,
|
|
/// U+006D
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
SmallM = 109,
|
|
/// U+006E
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
SmallN = 110,
|
|
/// U+006F
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
SmallO = 111,
|
|
/// U+0070
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
SmallP = 112,
|
|
/// U+0071
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
SmallQ = 113,
|
|
/// U+0072
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
SmallR = 114,
|
|
/// U+0073
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
SmallS = 115,
|
|
/// U+0074
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
SmallT = 116,
|
|
/// U+0075
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
SmallU = 117,
|
|
/// U+0076
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
SmallV = 118,
|
|
/// U+0077
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
SmallW = 119,
|
|
/// U+0078
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
SmallX = 120,
|
|
/// U+0079
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
SmallY = 121,
|
|
/// U+007A
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
SmallZ = 122,
|
|
/// U+007B
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
LeftCurlyBracket = 123,
|
|
/// U+007C
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
VerticalLine = 124,
|
|
/// U+007D
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
RightCurlyBracket = 125,
|
|
/// U+007E
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
Tilde = 126,
|
|
/// U+007F
|
|
#[unstable(feature = "ascii_char_variants", issue = "110998")]
|
|
Delete = 127,
|
|
}
|
|
|
|
impl AsciiChar {
|
|
/// The character with the lowest ASCII code.
|
|
#[unstable(feature = "ascii_char", issue = "110998")]
|
|
pub const MIN: Self = Self::Null;
|
|
|
|
/// The character with the highest ASCII code.
|
|
#[unstable(feature = "ascii_char", issue = "110998")]
|
|
pub const MAX: Self = Self::Delete;
|
|
|
|
/// Creates an ASCII character from the byte `b`,
|
|
/// or returns `None` if it's too large.
|
|
#[unstable(feature = "ascii_char", issue = "110998")]
|
|
#[inline]
|
|
pub const fn from_u8(b: u8) -> Option<Self> {
|
|
if b <= 127 {
|
|
// SAFETY: Just checked that `b` is in-range
|
|
Some(unsafe { Self::from_u8_unchecked(b) })
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
/// Creates an ASCII character from the byte `b`,
|
|
/// without checking whether it's valid.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// `b` must be in `0..=127`, or else this is UB.
|
|
#[unstable(feature = "ascii_char", issue = "110998")]
|
|
#[inline]
|
|
pub const unsafe fn from_u8_unchecked(b: u8) -> Self {
|
|
// SAFETY: Our safety precondition is that `b` is in-range.
|
|
unsafe { transmute(b) }
|
|
}
|
|
|
|
/// When passed the *number* `0`, `1`, …, `9`, returns the *character*
|
|
/// `'0'`, `'1'`, …, `'9'` respectively.
|
|
///
|
|
/// If `d >= 10`, returns `None`.
|
|
#[unstable(feature = "ascii_char", issue = "110998")]
|
|
#[inline]
|
|
pub const fn digit(d: u8) -> Option<Self> {
|
|
if d < 10 {
|
|
// SAFETY: Just checked it's in-range.
|
|
Some(unsafe { Self::digit_unchecked(d) })
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
/// When passed the *number* `0`, `1`, …, `9`, returns the *character*
|
|
/// `'0'`, `'1'`, …, `'9'` respectively, without checking that it's in-range.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// This is immediate UB if called with `d > 64`.
|
|
///
|
|
/// If `d >= 10` and `d <= 64`, this is allowed to return any value or panic.
|
|
/// Notably, it should not be expected to return hex digits, or any other
|
|
/// reasonable extension of the decimal digits.
|
|
///
|
|
/// (This loose safety condition is intended to simplify soundness proofs
|
|
/// when writing code using this method, since the implementation doesn't
|
|
/// need something really specific, not to make those other arguments do
|
|
/// something useful. It might be tightened before stabilization.)
|
|
#[unstable(feature = "ascii_char", issue = "110998")]
|
|
#[inline]
|
|
#[track_caller]
|
|
pub const unsafe fn digit_unchecked(d: u8) -> Self {
|
|
assert_unsafe_precondition!(
|
|
check_library_ub,
|
|
"`ascii::Char::digit_unchecked` input cannot exceed 9.",
|
|
(d: u8 = d) => d < 10
|
|
);
|
|
|
|
// SAFETY: `'0'` through `'9'` are U+00030 through U+0039,
|
|
// so because `d` must be 64 or less the addition can return at most
|
|
// 112 (0x70), which doesn't overflow and is within the ASCII range.
|
|
unsafe {
|
|
let byte = b'0'.unchecked_add(d);
|
|
Self::from_u8_unchecked(byte)
|
|
}
|
|
}
|
|
|
|
/// Gets this ASCII character as a byte.
|
|
#[unstable(feature = "ascii_char", issue = "110998")]
|
|
#[inline]
|
|
pub const fn to_u8(self) -> u8 {
|
|
self as u8
|
|
}
|
|
|
|
/// Gets this ASCII character as a `char` Unicode Scalar Value.
|
|
#[unstable(feature = "ascii_char", issue = "110998")]
|
|
#[inline]
|
|
pub const fn to_char(self) -> char {
|
|
self as u8 as char
|
|
}
|
|
|
|
/// Views this ASCII character as a one-code-unit UTF-8 `str`.
|
|
#[unstable(feature = "ascii_char", issue = "110998")]
|
|
#[inline]
|
|
pub const fn as_str(&self) -> &str {
|
|
crate::slice::from_ref(self).as_str()
|
|
}
|
|
|
|
/// Makes a copy of the value in its upper case equivalent.
|
|
///
|
|
/// Letters 'a' to 'z' are mapped to 'A' to 'Z'.
|
|
///
|
|
/// To uppercase the value in-place, use [`make_uppercase`].
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// #![feature(ascii_char, ascii_char_variants)]
|
|
/// use std::ascii;
|
|
///
|
|
/// let lowercase_a = ascii::Char::SmallA;
|
|
///
|
|
/// assert_eq!(
|
|
/// ascii::Char::CapitalA,
|
|
/// lowercase_a.to_uppercase(),
|
|
/// );
|
|
/// ```
|
|
///
|
|
/// [`make_uppercase`]: Self::make_uppercase
|
|
#[must_use = "to uppercase the value in-place, use `make_uppercase()`"]
|
|
#[unstable(feature = "ascii_char", issue = "110998")]
|
|
#[inline]
|
|
pub const fn to_uppercase(self) -> Self {
|
|
let uppercase_byte = self.to_u8().to_ascii_uppercase();
|
|
// SAFETY: Toggling the 6th bit won't convert ASCII to non-ASCII.
|
|
unsafe { Self::from_u8_unchecked(uppercase_byte) }
|
|
}
|
|
|
|
/// Makes a copy of the value in its lower case equivalent.
|
|
///
|
|
/// Letters 'A' to 'Z' are mapped to 'a' to 'z'.
|
|
///
|
|
/// To lowercase the value in-place, use [`make_lowercase`].
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// #![feature(ascii_char, ascii_char_variants)]
|
|
/// use std::ascii;
|
|
///
|
|
/// let uppercase_a = ascii::Char::CapitalA;
|
|
///
|
|
/// assert_eq!(
|
|
/// ascii::Char::SmallA,
|
|
/// uppercase_a.to_lowercase(),
|
|
/// );
|
|
/// ```
|
|
///
|
|
/// [`make_lowercase`]: Self::make_lowercase
|
|
#[must_use = "to lowercase the value in-place, use `make_lowercase()`"]
|
|
#[unstable(feature = "ascii_char", issue = "110998")]
|
|
#[inline]
|
|
pub const fn to_lowercase(self) -> Self {
|
|
let lowercase_byte = self.to_u8().to_ascii_lowercase();
|
|
// SAFETY: Setting the 6th bit won't convert ASCII to non-ASCII.
|
|
unsafe { Self::from_u8_unchecked(lowercase_byte) }
|
|
}
|
|
|
|
/// Checks that two values are a case-insensitive match.
|
|
///
|
|
/// This is equivalent to `to_lowercase(a) == to_lowercase(b)`.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// #![feature(ascii_char, ascii_char_variants)]
|
|
/// use std::ascii;
|
|
///
|
|
/// let lowercase_a = ascii::Char::SmallA;
|
|
/// let uppercase_a = ascii::Char::CapitalA;
|
|
///
|
|
/// assert!(lowercase_a.eq_ignore_case(uppercase_a));
|
|
/// ```
|
|
#[unstable(feature = "ascii_char", issue = "110998")]
|
|
#[inline]
|
|
pub const fn eq_ignore_case(self, other: Self) -> bool {
|
|
// FIXME(const-hack) `arg.to_u8().to_ascii_lowercase()` -> `arg.to_lowercase()`
|
|
// once `PartialEq` is const for `Self`.
|
|
self.to_u8().to_ascii_lowercase() == other.to_u8().to_ascii_lowercase()
|
|
}
|
|
|
|
/// Converts this value to its upper case equivalent in-place.
|
|
///
|
|
/// Letters 'a' to 'z' are mapped to 'A' to 'Z'.
|
|
///
|
|
/// To return a new uppercased value without modifying the existing one, use
|
|
/// [`to_uppercase`].
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// #![feature(ascii_char, ascii_char_variants)]
|
|
/// use std::ascii;
|
|
///
|
|
/// let mut letter_a = ascii::Char::SmallA;
|
|
///
|
|
/// letter_a.make_uppercase();
|
|
///
|
|
/// assert_eq!(ascii::Char::CapitalA, letter_a);
|
|
/// ```
|
|
///
|
|
/// [`to_uppercase`]: Self::to_uppercase
|
|
#[unstable(feature = "ascii_char", issue = "110998")]
|
|
#[inline]
|
|
pub const fn make_uppercase(&mut self) {
|
|
*self = self.to_uppercase();
|
|
}
|
|
|
|
/// Converts this value to its lower case equivalent in-place.
|
|
///
|
|
/// Letters 'A' to 'Z' are mapped to 'a' to 'z'.
|
|
///
|
|
/// To return a new lowercased value without modifying the existing one, use
|
|
/// [`to_lowercase`].
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// #![feature(ascii_char, ascii_char_variants)]
|
|
/// use std::ascii;
|
|
///
|
|
/// let mut letter_a = ascii::Char::CapitalA;
|
|
///
|
|
/// letter_a.make_lowercase();
|
|
///
|
|
/// assert_eq!(ascii::Char::SmallA, letter_a);
|
|
/// ```
|
|
///
|
|
/// [`to_lowercase`]: Self::to_lowercase
|
|
#[unstable(feature = "ascii_char", issue = "110998")]
|
|
#[inline]
|
|
pub const fn make_lowercase(&mut self) {
|
|
*self = self.to_lowercase();
|
|
}
|
|
|
|
/// Checks if the value is an alphabetic character:
|
|
///
|
|
/// - 0x41 'A' ..= 0x5A 'Z', or
|
|
/// - 0x61 'a' ..= 0x7A 'z'.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// #![feature(ascii_char, ascii_char_variants)]
|
|
/// use std::ascii;
|
|
///
|
|
/// let uppercase_a = ascii::Char::CapitalA;
|
|
/// let uppercase_g = ascii::Char::CapitalG;
|
|
/// let a = ascii::Char::SmallA;
|
|
/// let g = ascii::Char::SmallG;
|
|
/// let zero = ascii::Char::Digit0;
|
|
/// let percent = ascii::Char::PercentSign;
|
|
/// let space = ascii::Char::Space;
|
|
/// let lf = ascii::Char::LineFeed;
|
|
/// let esc = ascii::Char::Escape;
|
|
///
|
|
/// assert!(uppercase_a.is_alphabetic());
|
|
/// assert!(uppercase_g.is_alphabetic());
|
|
/// assert!(a.is_alphabetic());
|
|
/// assert!(g.is_alphabetic());
|
|
/// assert!(!zero.is_alphabetic());
|
|
/// assert!(!percent.is_alphabetic());
|
|
/// assert!(!space.is_alphabetic());
|
|
/// assert!(!lf.is_alphabetic());
|
|
/// assert!(!esc.is_alphabetic());
|
|
/// ```
|
|
#[must_use]
|
|
#[unstable(feature = "ascii_char", issue = "110998")]
|
|
#[inline]
|
|
pub const fn is_alphabetic(self) -> bool {
|
|
self.to_u8().is_ascii_alphabetic()
|
|
}
|
|
|
|
/// Checks if the value is an uppercase character:
|
|
/// 0x41 'A' ..= 0x5A 'Z'.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// #![feature(ascii_char, ascii_char_variants)]
|
|
/// use std::ascii;
|
|
///
|
|
/// let uppercase_a = ascii::Char::CapitalA;
|
|
/// let uppercase_g = ascii::Char::CapitalG;
|
|
/// let a = ascii::Char::SmallA;
|
|
/// let g = ascii::Char::SmallG;
|
|
/// let zero = ascii::Char::Digit0;
|
|
/// let percent = ascii::Char::PercentSign;
|
|
/// let space = ascii::Char::Space;
|
|
/// let lf = ascii::Char::LineFeed;
|
|
/// let esc = ascii::Char::Escape;
|
|
///
|
|
/// assert!(uppercase_a.is_uppercase());
|
|
/// assert!(uppercase_g.is_uppercase());
|
|
/// assert!(!a.is_uppercase());
|
|
/// assert!(!g.is_uppercase());
|
|
/// assert!(!zero.is_uppercase());
|
|
/// assert!(!percent.is_uppercase());
|
|
/// assert!(!space.is_uppercase());
|
|
/// assert!(!lf.is_uppercase());
|
|
/// assert!(!esc.is_uppercase());
|
|
/// ```
|
|
#[must_use]
|
|
#[unstable(feature = "ascii_char", issue = "110998")]
|
|
#[inline]
|
|
pub const fn is_uppercase(self) -> bool {
|
|
self.to_u8().is_ascii_uppercase()
|
|
}
|
|
|
|
/// Checks if the value is a lowercase character:
|
|
/// 0x61 'a' ..= 0x7A 'z'.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// #![feature(ascii_char, ascii_char_variants)]
|
|
/// use std::ascii;
|
|
///
|
|
/// let uppercase_a = ascii::Char::CapitalA;
|
|
/// let uppercase_g = ascii::Char::CapitalG;
|
|
/// let a = ascii::Char::SmallA;
|
|
/// let g = ascii::Char::SmallG;
|
|
/// let zero = ascii::Char::Digit0;
|
|
/// let percent = ascii::Char::PercentSign;
|
|
/// let space = ascii::Char::Space;
|
|
/// let lf = ascii::Char::LineFeed;
|
|
/// let esc = ascii::Char::Escape;
|
|
///
|
|
/// assert!(!uppercase_a.is_lowercase());
|
|
/// assert!(!uppercase_g.is_lowercase());
|
|
/// assert!(a.is_lowercase());
|
|
/// assert!(g.is_lowercase());
|
|
/// assert!(!zero.is_lowercase());
|
|
/// assert!(!percent.is_lowercase());
|
|
/// assert!(!space.is_lowercase());
|
|
/// assert!(!lf.is_lowercase());
|
|
/// assert!(!esc.is_lowercase());
|
|
/// ```
|
|
#[must_use]
|
|
#[unstable(feature = "ascii_char", issue = "110998")]
|
|
#[inline]
|
|
pub const fn is_lowercase(self) -> bool {
|
|
self.to_u8().is_ascii_lowercase()
|
|
}
|
|
|
|
/// Checks if the value is an alphanumeric character:
|
|
///
|
|
/// - 0x41 'A' ..= 0x5A 'Z', or
|
|
/// - 0x61 'a' ..= 0x7A 'z', or
|
|
/// - 0x30 '0' ..= 0x39 '9'.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// #![feature(ascii_char, ascii_char_variants)]
|
|
/// use std::ascii;
|
|
///
|
|
/// let uppercase_a = ascii::Char::CapitalA;
|
|
/// let uppercase_g = ascii::Char::CapitalG;
|
|
/// let a = ascii::Char::SmallA;
|
|
/// let g = ascii::Char::SmallG;
|
|
/// let zero = ascii::Char::Digit0;
|
|
/// let percent = ascii::Char::PercentSign;
|
|
/// let space = ascii::Char::Space;
|
|
/// let lf = ascii::Char::LineFeed;
|
|
/// let esc = ascii::Char::Escape;
|
|
///
|
|
/// assert!(uppercase_a.is_alphanumeric());
|
|
/// assert!(uppercase_g.is_alphanumeric());
|
|
/// assert!(a.is_alphanumeric());
|
|
/// assert!(g.is_alphanumeric());
|
|
/// assert!(zero.is_alphanumeric());
|
|
/// assert!(!percent.is_alphanumeric());
|
|
/// assert!(!space.is_alphanumeric());
|
|
/// assert!(!lf.is_alphanumeric());
|
|
/// assert!(!esc.is_alphanumeric());
|
|
/// ```
|
|
#[must_use]
|
|
#[unstable(feature = "ascii_char", issue = "110998")]
|
|
#[inline]
|
|
pub const fn is_alphanumeric(self) -> bool {
|
|
self.to_u8().is_ascii_alphanumeric()
|
|
}
|
|
|
|
/// Checks if the value is a decimal digit:
|
|
/// 0x30 '0' ..= 0x39 '9'.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// #![feature(ascii_char, ascii_char_variants)]
|
|
/// use std::ascii;
|
|
///
|
|
/// let uppercase_a = ascii::Char::CapitalA;
|
|
/// let uppercase_g = ascii::Char::CapitalG;
|
|
/// let a = ascii::Char::SmallA;
|
|
/// let g = ascii::Char::SmallG;
|
|
/// let zero = ascii::Char::Digit0;
|
|
/// let percent = ascii::Char::PercentSign;
|
|
/// let space = ascii::Char::Space;
|
|
/// let lf = ascii::Char::LineFeed;
|
|
/// let esc = ascii::Char::Escape;
|
|
///
|
|
/// assert!(!uppercase_a.is_digit());
|
|
/// assert!(!uppercase_g.is_digit());
|
|
/// assert!(!a.is_digit());
|
|
/// assert!(!g.is_digit());
|
|
/// assert!(zero.is_digit());
|
|
/// assert!(!percent.is_digit());
|
|
/// assert!(!space.is_digit());
|
|
/// assert!(!lf.is_digit());
|
|
/// assert!(!esc.is_digit());
|
|
/// ```
|
|
#[must_use]
|
|
#[unstable(feature = "ascii_char", issue = "110998")]
|
|
#[inline]
|
|
pub const fn is_digit(self) -> bool {
|
|
self.to_u8().is_ascii_digit()
|
|
}
|
|
|
|
/// Checks if the value is an octal digit:
|
|
/// 0x30 '0' ..= 0x37 '7'.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// #![feature(ascii_char, ascii_char_variants)]
|
|
///
|
|
/// use std::ascii;
|
|
///
|
|
/// let uppercase_a = ascii::Char::CapitalA;
|
|
/// let a = ascii::Char::SmallA;
|
|
/// let zero = ascii::Char::Digit0;
|
|
/// let seven = ascii::Char::Digit7;
|
|
/// let eight = ascii::Char::Digit8;
|
|
/// let percent = ascii::Char::PercentSign;
|
|
/// let lf = ascii::Char::LineFeed;
|
|
/// let esc = ascii::Char::Escape;
|
|
///
|
|
/// assert!(!uppercase_a.is_octdigit());
|
|
/// assert!(!a.is_octdigit());
|
|
/// assert!(zero.is_octdigit());
|
|
/// assert!(seven.is_octdigit());
|
|
/// assert!(!eight.is_octdigit());
|
|
/// assert!(!percent.is_octdigit());
|
|
/// assert!(!lf.is_octdigit());
|
|
/// assert!(!esc.is_octdigit());
|
|
/// ```
|
|
#[must_use]
|
|
// This is blocked on two unstable features. Please ensure both are
|
|
// stabilized before marking this method as stable.
|
|
#[unstable(feature = "ascii_char", issue = "110998")]
|
|
// #[unstable(feature = "is_ascii_octdigit", issue = "101288")]
|
|
#[inline]
|
|
pub const fn is_octdigit(self) -> bool {
|
|
self.to_u8().is_ascii_octdigit()
|
|
}
|
|
|
|
/// Checks if the value is a hexadecimal digit:
|
|
///
|
|
/// - 0x30 '0' ..= 0x39 '9', or
|
|
/// - 0x41 'A' ..= 0x46 'F', or
|
|
/// - 0x61 'a' ..= 0x66 'f'.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// #![feature(ascii_char, ascii_char_variants)]
|
|
/// use std::ascii;
|
|
///
|
|
/// let uppercase_a = ascii::Char::CapitalA;
|
|
/// let uppercase_g = ascii::Char::CapitalG;
|
|
/// let a = ascii::Char::SmallA;
|
|
/// let g = ascii::Char::SmallG;
|
|
/// let zero = ascii::Char::Digit0;
|
|
/// let percent = ascii::Char::PercentSign;
|
|
/// let space = ascii::Char::Space;
|
|
/// let lf = ascii::Char::LineFeed;
|
|
/// let esc = ascii::Char::Escape;
|
|
///
|
|
/// assert!(uppercase_a.is_hexdigit());
|
|
/// assert!(!uppercase_g.is_hexdigit());
|
|
/// assert!(a.is_hexdigit());
|
|
/// assert!(!g.is_hexdigit());
|
|
/// assert!(zero.is_hexdigit());
|
|
/// assert!(!percent.is_hexdigit());
|
|
/// assert!(!space.is_hexdigit());
|
|
/// assert!(!lf.is_hexdigit());
|
|
/// assert!(!esc.is_hexdigit());
|
|
/// ```
|
|
#[must_use]
|
|
#[unstable(feature = "ascii_char", issue = "110998")]
|
|
#[inline]
|
|
pub const fn is_hexdigit(self) -> bool {
|
|
self.to_u8().is_ascii_hexdigit()
|
|
}
|
|
|
|
/// Checks if the value is a punctuation character:
|
|
///
|
|
/// - 0x21 ..= 0x2F `! " # $ % & ' ( ) * + , - . /`, or
|
|
/// - 0x3A ..= 0x40 `: ; < = > ? @`, or
|
|
/// - 0x5B ..= 0x60 `` [ \ ] ^ _ ` ``, or
|
|
/// - 0x7B ..= 0x7E `{ | } ~`
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// #![feature(ascii_char, ascii_char_variants)]
|
|
/// use std::ascii;
|
|
///
|
|
/// let uppercase_a = ascii::Char::CapitalA;
|
|
/// let uppercase_g = ascii::Char::CapitalG;
|
|
/// let a = ascii::Char::SmallA;
|
|
/// let g = ascii::Char::SmallG;
|
|
/// let zero = ascii::Char::Digit0;
|
|
/// let percent = ascii::Char::PercentSign;
|
|
/// let space = ascii::Char::Space;
|
|
/// let lf = ascii::Char::LineFeed;
|
|
/// let esc = ascii::Char::Escape;
|
|
///
|
|
/// assert!(!uppercase_a.is_punctuation());
|
|
/// assert!(!uppercase_g.is_punctuation());
|
|
/// assert!(!a.is_punctuation());
|
|
/// assert!(!g.is_punctuation());
|
|
/// assert!(!zero.is_punctuation());
|
|
/// assert!(percent.is_punctuation());
|
|
/// assert!(!space.is_punctuation());
|
|
/// assert!(!lf.is_punctuation());
|
|
/// assert!(!esc.is_punctuation());
|
|
/// ```
|
|
#[must_use]
|
|
#[unstable(feature = "ascii_char", issue = "110998")]
|
|
#[inline]
|
|
pub const fn is_punctuation(self) -> bool {
|
|
self.to_u8().is_ascii_punctuation()
|
|
}
|
|
|
|
/// Checks if the value is a graphic character:
|
|
/// 0x21 '!' ..= 0x7E '~'.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// #![feature(ascii_char, ascii_char_variants)]
|
|
/// use std::ascii;
|
|
///
|
|
/// let uppercase_a = ascii::Char::CapitalA;
|
|
/// let uppercase_g = ascii::Char::CapitalG;
|
|
/// let a = ascii::Char::SmallA;
|
|
/// let g = ascii::Char::SmallG;
|
|
/// let zero = ascii::Char::Digit0;
|
|
/// let percent = ascii::Char::PercentSign;
|
|
/// let space = ascii::Char::Space;
|
|
/// let lf = ascii::Char::LineFeed;
|
|
/// let esc = ascii::Char::Escape;
|
|
///
|
|
/// assert!(uppercase_a.is_graphic());
|
|
/// assert!(uppercase_g.is_graphic());
|
|
/// assert!(a.is_graphic());
|
|
/// assert!(g.is_graphic());
|
|
/// assert!(zero.is_graphic());
|
|
/// assert!(percent.is_graphic());
|
|
/// assert!(!space.is_graphic());
|
|
/// assert!(!lf.is_graphic());
|
|
/// assert!(!esc.is_graphic());
|
|
/// ```
|
|
#[must_use]
|
|
#[unstable(feature = "ascii_char", issue = "110998")]
|
|
#[inline]
|
|
pub const fn is_graphic(self) -> bool {
|
|
self.to_u8().is_ascii_graphic()
|
|
}
|
|
|
|
/// Checks if the value is a whitespace character:
|
|
/// 0x20 SPACE, 0x09 HORIZONTAL TAB, 0x0A LINE FEED,
|
|
/// 0x0C FORM FEED, or 0x0D CARRIAGE RETURN.
|
|
///
|
|
/// Rust uses the WhatWG Infra Standard's [definition of ASCII
|
|
/// whitespace][infra-aw]. There are several other definitions in
|
|
/// wide use. For instance, [the POSIX locale][pct] includes
|
|
/// 0x0B VERTICAL TAB as well as all the above characters,
|
|
/// but—from the very same specification—[the default rule for
|
|
/// "field splitting" in the Bourne shell][bfs] considers *only*
|
|
/// SPACE, HORIZONTAL TAB, and LINE FEED as whitespace.
|
|
///
|
|
/// If you are writing a program that will process an existing
|
|
/// file format, check what that format's definition of whitespace is
|
|
/// before using this function.
|
|
///
|
|
/// [infra-aw]: https://infra.spec.whatwg.org/#ascii-whitespace
|
|
/// [pct]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_01
|
|
/// [bfs]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// #![feature(ascii_char, ascii_char_variants)]
|
|
/// use std::ascii;
|
|
///
|
|
/// let uppercase_a = ascii::Char::CapitalA;
|
|
/// let uppercase_g = ascii::Char::CapitalG;
|
|
/// let a = ascii::Char::SmallA;
|
|
/// let g = ascii::Char::SmallG;
|
|
/// let zero = ascii::Char::Digit0;
|
|
/// let percent = ascii::Char::PercentSign;
|
|
/// let space = ascii::Char::Space;
|
|
/// let lf = ascii::Char::LineFeed;
|
|
/// let esc = ascii::Char::Escape;
|
|
///
|
|
/// assert!(!uppercase_a.is_whitespace());
|
|
/// assert!(!uppercase_g.is_whitespace());
|
|
/// assert!(!a.is_whitespace());
|
|
/// assert!(!g.is_whitespace());
|
|
/// assert!(!zero.is_whitespace());
|
|
/// assert!(!percent.is_whitespace());
|
|
/// assert!(space.is_whitespace());
|
|
/// assert!(lf.is_whitespace());
|
|
/// assert!(!esc.is_whitespace());
|
|
/// ```
|
|
#[must_use]
|
|
#[unstable(feature = "ascii_char", issue = "110998")]
|
|
#[inline]
|
|
pub const fn is_whitespace(self) -> bool {
|
|
self.to_u8().is_ascii_whitespace()
|
|
}
|
|
|
|
/// Checks if the value is a control character:
|
|
/// 0x00 NUL ..= 0x1F UNIT SEPARATOR, or 0x7F DELETE.
|
|
/// Note that most whitespace characters are control
|
|
/// characters, but SPACE is not.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// #![feature(ascii_char, ascii_char_variants)]
|
|
/// use std::ascii;
|
|
///
|
|
/// let uppercase_a = ascii::Char::CapitalA;
|
|
/// let uppercase_g = ascii::Char::CapitalG;
|
|
/// let a = ascii::Char::SmallA;
|
|
/// let g = ascii::Char::SmallG;
|
|
/// let zero = ascii::Char::Digit0;
|
|
/// let percent = ascii::Char::PercentSign;
|
|
/// let space = ascii::Char::Space;
|
|
/// let lf = ascii::Char::LineFeed;
|
|
/// let esc = ascii::Char::Escape;
|
|
///
|
|
/// assert!(!uppercase_a.is_control());
|
|
/// assert!(!uppercase_g.is_control());
|
|
/// assert!(!a.is_control());
|
|
/// assert!(!g.is_control());
|
|
/// assert!(!zero.is_control());
|
|
/// assert!(!percent.is_control());
|
|
/// assert!(!space.is_control());
|
|
/// assert!(lf.is_control());
|
|
/// assert!(esc.is_control());
|
|
/// ```
|
|
#[must_use]
|
|
#[unstable(feature = "ascii_char", issue = "110998")]
|
|
#[inline]
|
|
pub const fn is_control(self) -> bool {
|
|
self.to_u8().is_ascii_control()
|
|
}
|
|
|
|
/// Returns an iterator that produces an escaped version of a
|
|
/// character.
|
|
///
|
|
/// The behavior is identical to
|
|
/// [`ascii::escape_default`](crate::ascii::escape_default).
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// #![feature(ascii_char, ascii_char_variants)]
|
|
/// use std::ascii;
|
|
///
|
|
/// let zero = ascii::Char::Digit0;
|
|
/// let tab = ascii::Char::CharacterTabulation;
|
|
/// let cr = ascii::Char::CarriageReturn;
|
|
/// let lf = ascii::Char::LineFeed;
|
|
/// let apostrophe = ascii::Char::Apostrophe;
|
|
/// let double_quote = ascii::Char::QuotationMark;
|
|
/// let backslash = ascii::Char::ReverseSolidus;
|
|
///
|
|
/// assert_eq!("0", zero.escape_ascii().to_string());
|
|
/// assert_eq!("\\t", tab.escape_ascii().to_string());
|
|
/// assert_eq!("\\r", cr.escape_ascii().to_string());
|
|
/// assert_eq!("\\n", lf.escape_ascii().to_string());
|
|
/// assert_eq!("\\'", apostrophe.escape_ascii().to_string());
|
|
/// assert_eq!("\\\"", double_quote.escape_ascii().to_string());
|
|
/// assert_eq!("\\\\", backslash.escape_ascii().to_string());
|
|
/// ```
|
|
#[must_use = "this returns the escaped character as an iterator, \
|
|
without modifying the original"]
|
|
#[unstable(feature = "ascii_char", issue = "110998")]
|
|
#[inline]
|
|
pub fn escape_ascii(self) -> super::EscapeDefault {
|
|
super::escape_default(self.to_u8())
|
|
}
|
|
}
|
|
|
|
macro_rules! into_int_impl {
|
|
($($ty:ty)*) => {
|
|
$(
|
|
#[unstable(feature = "ascii_char", issue = "110998")]
|
|
#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
|
|
impl const From<AsciiChar> for $ty {
|
|
#[inline]
|
|
fn from(chr: AsciiChar) -> $ty {
|
|
chr as u8 as $ty
|
|
}
|
|
}
|
|
)*
|
|
}
|
|
}
|
|
|
|
into_int_impl!(u8 u16 u32 u64 u128 char);
|
|
|
|
impl [AsciiChar] {
|
|
/// Views this slice of ASCII characters as a UTF-8 `str`.
|
|
#[unstable(feature = "ascii_char", issue = "110998")]
|
|
#[inline]
|
|
pub const fn as_str(&self) -> &str {
|
|
let ascii_ptr: *const Self = self;
|
|
let str_ptr = ascii_ptr as *const str;
|
|
// SAFETY: Each ASCII codepoint in UTF-8 is encoded as one single-byte
|
|
// code unit having the same value as the ASCII byte.
|
|
unsafe { &*str_ptr }
|
|
}
|
|
|
|
/// Views this slice of ASCII characters as a slice of `u8` bytes.
|
|
#[unstable(feature = "ascii_char", issue = "110998")]
|
|
#[inline]
|
|
pub const fn as_bytes(&self) -> &[u8] {
|
|
self.as_str().as_bytes()
|
|
}
|
|
}
|
|
|
|
#[unstable(feature = "ascii_char", issue = "110998")]
|
|
impl fmt::Display for AsciiChar {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
<str as fmt::Display>::fmt(self.as_str(), f)
|
|
}
|
|
}
|
|
|
|
#[unstable(feature = "ascii_char", issue = "110998")]
|
|
impl fmt::Debug for AsciiChar {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
use AsciiChar::{Apostrophe, Null, ReverseSolidus as Backslash};
|
|
|
|
fn backslash(a: AsciiChar) -> ([AsciiChar; 6], usize) {
|
|
([Apostrophe, Backslash, a, Apostrophe, Null, Null], 4)
|
|
}
|
|
|
|
let (buf, len) = match self {
|
|
AsciiChar::Null => backslash(AsciiChar::Digit0),
|
|
AsciiChar::CharacterTabulation => backslash(AsciiChar::SmallT),
|
|
AsciiChar::CarriageReturn => backslash(AsciiChar::SmallR),
|
|
AsciiChar::LineFeed => backslash(AsciiChar::SmallN),
|
|
AsciiChar::ReverseSolidus => backslash(AsciiChar::ReverseSolidus),
|
|
AsciiChar::Apostrophe => backslash(AsciiChar::Apostrophe),
|
|
_ if self.to_u8().is_ascii_control() => {
|
|
const HEX_DIGITS: [AsciiChar; 16] = *b"0123456789abcdef".as_ascii().unwrap();
|
|
|
|
let byte = self.to_u8();
|
|
let hi = HEX_DIGITS[usize::from(byte >> 4)];
|
|
let lo = HEX_DIGITS[usize::from(byte & 0xf)];
|
|
([Apostrophe, Backslash, AsciiChar::SmallX, hi, lo, Apostrophe], 6)
|
|
}
|
|
_ => ([Apostrophe, *self, Apostrophe, Null, Null, Null], 3),
|
|
};
|
|
|
|
f.write_str(buf[..len].as_str())
|
|
}
|
|
}
|