//! 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 `` 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 { 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 { 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, is_ascii_octdigit)] /// /// 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 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 { ::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()) } }