Change:
As discussed at I have equivalents of most (not quite all) of C's 's functions to the AsciiExt trait. The new functions are (matches the , not POSIX) They are implemented for , , , and , and, for backward compatibility with external trait implementations, have default implementations that call . PR to follow, but I needed to file this bug in order to get an issue number to put in the stability annotations.
Stabilize? I just wrote , it’s not too bad but might have looked nicer as
There was a request over in to deprecate and convert all the methods to intrinsics on , , etc. but I never got around to it and don't have time in the near future either. I dunno how a plan to do that would affect the stabilization schedule.
What's the status here? Could I try to "deprecate AsciiExt and convert all the methods to intrinsics on , ", create a PR and it might be accepted? Or are there other plans? If there is nothing except "lack of time" blocking this, I might be able to help.
From my end it's just lack of time. I think the team would be glad to at least look at a patch if you made one.
Right now is implemented for and . When copying all methods to the individual types, shall I also copy them for and ? I kinda doubt those implementations are really useful. And it also doesn't make sense not to implement it for (e.g. an array of utf16 codepoints), too. What do you think?
I’ve definitely used , , and on and .
CC / for FCP to stabilize as inherent methods:
fcp merge
Team member has proposed to merge this. The next step is review by the rest of the tagged teams: [x] [x] [x] [x] [x] [x] Concerns: str and [u8] methods () Once these reviewers reach consensus, this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See for info about what commands tagged team members can give me.
The semantics of e.g. as meaning every byte is a hex digit is a bit of a stretch. Now that these are inherent methods rather than a common extension trait across char and str, we should consider that we no longer need all the methods across all the types. Is an ASCII hex digit? Sure. Is an ASCII hex digit? Not obvious to me. Is an ASCII hex digit? Would it be bad to require the user to be more explicit in some of these cases? concern str and [u8] methods
I think I agree with and given I think we should "soon" have the ability to implement that relatively easily?
Discussed at the libs triage meeting today, we're going to scope this issue to be blocked on and then we'll stabilize these methods only on the and types.
has landed
I would like to prepare a PR for stabilization. A few things: I would remove the inherent methods of and entirely I would replace the attribute with a one on the inherent methods for and . I should keep the feature name , right? I will remove all methods of the trait, ok? They are still unstable so we can remove them. Or do you want to keep them around for a bit and maybe deprecate them later? Is that even possible, to have an unstable and a stable feature with the same name? Anyway, removing them from seems like the best idea to me.
Sounds pretty good to me! It's ok to tweak the feature name if necessary (not critical to remain the same). I'd probably give the stable methods a new feature name to leave the unstable methods. Removing the methods from and makes sense to me as well. For now I'd also leave the methods on the trait and not delete anything just yet, we can do that once this has all hit stable.
Right now, the trait is implemented by just calling the inherent methods. It's done by a macro to avoid duplicate code. If we don't remove all methods from , I need to move the real implementation back to the impl and cannot use the macro for and anymore. It's not a tragedy, but it would be a bit annoying and produces a lot of diff noise. I'd prefer removing the methods on immediately. But I can understand if we want to keep them around for a few cycles still. I just wanted to ask before I would move all the code around. What do you think?
yeah keeping code around for awhile to minimize the diff seems fine by me! I think we'll be leaving for awhile anyway
Any update here?
Rust 1.24 was recently released with these methods available as inherent methods of and . For example: I think we can now deprecate the trait. (And, a release cycle or two after that, perhaps remove its unstable methods.) This issue should probably be re-opened to track this.
Reopened as per request on IRC.
Is it still the plan to get at least , ,, and on ? It's a bit verbose to have to create an iterator over chars for each string.
We decided that we prefer the explicit version of (see ). I'd doubt that those methods will be to and anytime soon...
Deprecation PR for the trait:
Shouldn't this issue also track "removing of unstable methods"? Otherwise we might forget to remove those. Or was there already a PR doing that which I missed?
I don’t know how useful it is to track such features individually. We can occasionally do a pass on the entire standard library looking for items that are both unstable and have been deprecated for a while.
Ah, I missed the fact that the unstable methods were also marked deprecated. That makes sense then!
I'm disappointed that there is now no officially-supported version of and friends for . This was functionality I was using, and it's annoying to go back and write out fancy iterators everywhere or provide my own crate for that functionality. I understand moving this stuff out of , but could we please have the full functionality back?
IMO might have an unexpected behavior. On , the same method tells whether the character is in the range to , whether it is an ASCII lower-case letter. The "simple" generalization of that to strings is: is this string made entirely of ASCII lower-case letters? However, what one might be looking for, and not realize that is different is: if I were to call , would I obtain the same string? which really means does this string not contain any upper-case letter? Forcing users to write makes it apparent what a call actually does. (Maybe (respectively ) should be named something like instead…)
That is an interesting point. There are certainly a number of fine distinctions that can be drawn here: one might reasonably expect that might return true if and only if the target contained only lowercase alphabetic ASCII characters, for example. That said, I still feel like the crate already defined a behavior for this function, and that the right thing to do would be to preserve that functionality across the move, at least for now. It feels a bit iffy to me to remove existing functionality without going through the RFC process (as far as I can tell?) in the interest of protecting users from using functions wrong. Do we have evidence that people have routinely misunderstood or misused ? Its documentation seemed pretty clear to me. There's an underlying problem here in that anything we do to make ASCII more of a first-class citizen is a step toward encouraging folks to routinely write ASCII-only programs. Nobody wants that. Having said that, tutorials and examples almost always use and pretty much depend on ASCII: things like Exercism and the Advent Of Code series have caused me an occasional "any other language" kind of feeling because the exercises just assume quality ASCII support. Asking newer users to understand how to write the appropriate iterators to complete these exercises seems to me like it might have its own set of issues. I don't know. I guess I just need to identify or write a crate that has good support for ASCII-only strings and chars and start using it in situations where that's what I'm working with. was never that, and so maybe removing it makes a hole that can be filled with something better. (A quick survey of the crate looks promising, although I'd still have to add the string functions, looks like. It's been downloaded quite a lot, which might indicate a real demand for this kind of thing.) For now, it is, I guess.
For what it’s worth the addition of never went through the RFC process in the first place. Interesting, because this behavior is neither (that’s ) nor what I had in mind for the alternative behavior (, without checking that the string is entirely ASCII). Anyway, it’s always possible to add more methods but a closed issue may not be the best place to propose them.

Discussion:
/// [`to_ascii_lowercase`]: #tymethod.to_ascii_lowercase #[stable(feature = "ascii", since = "1.9.0")] fn make_ascii_lowercase(&mut self); <ins> /// Checks if the value is an ASCII alphabetic character: /// U+0041 'A' ... U+005A 'Z' or U+0061 'a' ... U+007A 'z'. /// For strings, true if all characters in the string are /// ASCII alphabetic. /// /// # Examples /// /// ``` /// #![feature(ascii_ctype)] /// # #![allow(non_snake_case)] /// use std::ascii::AsciiExt; /// let A = 'A'; /// let G = 'G'; /// let a = 'a'; /// let g = 'g'; /// let zero = '0'; /// let percent = '%'; /// let space = ' '; /// let lf = 'n'; /// let esc = 'u{001b}'; /// /// assert!(A.is_ascii_alphabetic()); /// assert!(G.is_ascii_alphabetic()); /// assert!(a.is_ascii_alphabetic()); /// assert!(g.is_ascii_alphabetic()); /// assert!(!zero.is_ascii_alphabetic()); /// assert!(!percent.is_ascii_alphabetic()); /// assert!(!space.is_ascii_alphabetic()); /// assert!(!lf.is_ascii_alphabetic()); /// assert!(!esc.is_ascii_alphabetic()); /// ``` #[unstable(feature = "ascii_ctype", issue = "39658")] fn is_ascii_alphabetic(&self) -> bool { unimplemented!(); } /// Checks if the value is an ASCII uppercase character: /// U+0041 'A' ... U+005A 'Z'. /// For strings, true if all characters in the string are /// ASCII uppercase. /// /// # Examples /// /// ``` /// #![feature(ascii_ctype)] /// # #![allow(non_snake_case)] /// use std::ascii::AsciiExt; /// let A = 'A'; /// let G = 'G'; /// let a = 'a'; /// let g = 'g'; /// let zero = '0'; /// let percent = '%'; /// let space = ' '; /// let lf = 'n'; /// let esc = 'u{001b}'; /// /// assert!(A.is_ascii_uppercase()); /// assert!(G.is_ascii_uppercase()); /// assert!(!a.is_ascii_uppercase()); /// assert!(!g.is_ascii_uppercase()); /// assert!(!zero.is_ascii_uppercase()); /// assert!(!percent.is_ascii_uppercase()); /// assert!(!space.is_ascii_uppercase()); /// assert!(!lf.is_ascii_uppercase()); /// assert!(!esc.is_ascii_uppercase()); /// ``` #[unstable(feature = "ascii_ctype", issue = "39658")] fn is_ascii_uppercase(&self) -> bool { unimplemented!(); } /// Checks if the value is an ASCII lowercase character: /// U+0061 'a' ... U+007A 'z'. /// For strings, true if all characters in the string are /// ASCII lowercase. /// /// # Examples /// /// ``` /// #![feature(ascii_ctype)] /// # #![allow(non_snake_case)] /// use std::ascii::AsciiExt; /// let A = 'A'; /// let G = 'G'; /// let a = 'a'; /// let g = 'g'; /// let zero = '0'; /// let percent = '%'; /// let space = ' '; /// let lf = 'n'; /// let esc = 'u{001b}'; /// /// assert!(!A.is_ascii_lowercase()); /// assert!(!G.is_ascii_lowercase()); /// assert!(a.is_ascii_lowercase()); /// assert!(g.is_ascii_lowercase()); /// assert!(!zero.is_ascii_lowercase()); /// assert!(!percent.is_ascii_lowercase()); /// assert!(!space.is_ascii_lowercase()); /// assert!(!lf.is_ascii_lowercase()); /// assert!(!esc.is_ascii_lowercase()); /// ``` #[unstable(feature = "ascii_ctype", issue = "39658")] fn is_ascii_lowercase(&self) -> bool { unimplemented!(); } /// Checks if the value is an ASCII alphanumeric character: /// U+0041 'A' ... U+005A 'Z', U+0061 'a' ... U+007A 'z', or /// U+0030 '0' ... U+0039 '9'. /// For strings, true if all characters in the string are /// ASCII alphanumeric. /// /// # Examples /// /// ``` /// #![feature(ascii_ctype)] /// # #![allow(non_snake_case)] /// use std::ascii::AsciiExt; /// let A = 'A'; /// let G = 'G'; /// let a = 'a'; /// let g = 'g'; /// let zero = '0'; /// let percent = '%'; /// let space = ' '; /// let lf = 'n'; /// let esc = 'u{001b}'; /// /// assert!(A.is_ascii_alphanumeric()); /// assert!(G.is_ascii_alphanumeric()); /// assert!(a.is_ascii_alphanumeric()); /// assert!(g.is_ascii_alphanumeric()); /// assert!(zero.is_ascii_alphanumeric()); /// assert!(!percent.is_ascii_alphanumeric()); /// assert!(!space.is_ascii_alphanumeric()); /// assert!(!lf.is_ascii_alphanumeric()); /// assert!(!esc.is_ascii_alphanumeric()); /// ``` #[unstable(feature = "ascii_ctype", issue = "39658")] fn is_ascii_alphanumeric(&self) -> bool { unimplemented!(); } /// Checks if the value is an ASCII decimal digit: /// U+0030 '0' ... U+0039 '9'. /// For strings, true if all characters in the string are /// ASCII digits. /// /// # Examples /// /// ``` /// #![feature(ascii_ctype)] /// # #![allow(non_snake_case)] /// use std::ascii::AsciiExt; /// let A = 'A'; /// let G = 'G'; /// let a = 'a'; /// let g = 'g'; /// let zero = '0'; /// let percent = '%'; /// let space = ' '; /// let lf = 'n'; /// let esc = 'u{001b}'; /// /// assert!(!A.is_ascii_digit()); /// assert!(!G.is_ascii_digit()); /// assert!(!a.is_ascii_digit()); /// assert!(!g.is_ascii_digit()); /// assert!(zero.is_ascii_digit()); /// assert!(!percent.is_ascii_digit()); /// assert!(!space.is_ascii_digit()); /// assert!(!lf.is_ascii_digit()); /// assert!(!esc.is_ascii_digit()); /// ``` #[unstable(feature = "ascii_ctype", issue = "39658")] fn is_ascii_digit(&self) -> bool { unimplemented!(); } /// Checks if the value is an ASCII hexadecimal digit: /// U+0030 '0' ... U+0039 '9', U+0041 'A' ... U+0046 'F', or /// U+0061 'a' ... U+0066 'f'. /// For strings, true if all characters in the string are /// ASCII hex digits. /// /// # Examples /// /// ``` /// #![feature(ascii_ctype)] /// # #![allow(non_snake_case)] /// use std::ascii::AsciiExt; /// let A = 'A'; /// let G = 'G'; /// let a = 'a'; /// let g = 'g'; /// let zero = '0'; /// let percent = '%'; /// let space = ' '; /// let lf = 'n'; /// let esc = 'u{001b}'; /// /// assert!(A.is_ascii_hexdigit()); /// assert!(!G.is_ascii_hexdigit()); /// assert!(a.is_ascii_hexdigit()); /// assert!(!g.is_ascii_hexdigit()); /// assert!(zero.is_ascii_hexdigit()); /// assert!(!percent.is_ascii_hexdigit()); /// assert!(!space.is_ascii_hexdigit()); /// assert!(!lf.is_ascii_hexdigit()); /// assert!(!esc.is_ascii_hexdigit()); /// ``` #[unstable(feature = "ascii_ctype", issue = "39658")] fn is_ascii_hexdigit(&self) -> bool { unimplemented!(); } /// Checks if the value is an ASCII punctuation character: /// U+0021 ... U+002F `! " # $ % & ' ( ) * + , - . /` /// U+003A ... U+0040 `: ; < = > ? @` /// U+005B ... U+0060 `[  ] ^ _ `` /// U+007B ... U+007E `{ | } ~` /// For strings, true if all characters in the string are /// ASCII punctuation. /// /// # Examples /// /// ``` /// #![feature(ascii_ctype)] /// # #![allow(non_snake_case)] /// use std::ascii::AsciiExt; /// let A = 'A'; /// let G = 'G'; /// let a = 'a'; /// let g = 'g'; /// let zero = '0'; /// let percent = '%'; /// let space = ' '; /// let lf = 'n'; /// let esc = 'u{001b}'; /// /// assert!(!A.is_ascii_punctuation()); /// assert!(!G.is_ascii_punctuation()); /// assert!(!a.is_ascii_punctuation()); /// assert!(!g.is_ascii_punctuation()); /// assert!(!zero.is_ascii_punctuation()); /// assert!(percent.is_ascii_punctuation()); /// assert!(!space.is_ascii_punctuation()); /// assert!(!lf.is_ascii_punctuation()); /// assert!(!esc.is_ascii_punctuation()); /// ``` #[unstable(feature = "ascii_ctype", issue = "39658")] fn is_ascii_punctuation(&self) -> bool { unimplemented!(); } /// Checks if the value is an ASCII graphic character: /// U+0021 '@' ... U+007E '~'. /// For strings, true if all characters in the string are /// ASCII punctuation. /// /// # Examples /// /// ``` /// #![feature(ascii_ctype)] /// # #![allow(non_snake_case)] /// use std::ascii::AsciiExt; /// let A = 'A'; /// let G = 'G'; /// let a = 'a'; /// let g = 'g'; /// let zero = '0'; /// let percent = '%'; /// let space = ' '; /// let lf = 'n'; /// let esc = 'u{001b}'; /// /// assert!(A.is_ascii_graphic()); /// assert!(G.is_ascii_graphic()); /// assert!(a.is_ascii_graphic()); /// assert!(g.is_ascii_graphic()); /// assert!(zero.is_ascii_graphic()); /// assert!(percent.is_ascii_graphic()); /// assert!(!space.is_ascii_graphic()); /// assert!(!lf.is_ascii_graphic()); /// assert!(!esc.is_ascii_graphic()); /// ``` #[unstable(feature = "ascii_ctype", issue = "39658")] fn is_ascii_graphic(&self) -> bool { unimplemented!(); } /// Checks if the value is an ASCII whitespace character: /// U+0020 SPACE, U+0009 HORIZONTAL TAB, U+000A LINE FEED, /// U+000C FORM FEED, or U+000D CARRIAGE RETURN. /// For strings, true if all characters in the string are /// ASCII whitespace. /// /// 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 /// U+000B 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]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_01 /// [bfs]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 /// /// # Examples /// /// ``` /// #![feature(ascii_ctype)] /// # #![allow(non_snake_case)] /// use std::ascii::AsciiExt; /// let A = 'A'; /// let G = 'G'; /// let a = 'a'; /// let g = 'g'; /// let zero = '0'; /// let percent = '%'; /// let space = ' '; /// let lf = 'n'; /// let esc = 'u{001b}'; /// /// assert!(!A.is_ascii_whitespace()); /// assert!(!G.is_ascii_whitespace()); /// assert!(!a.is_ascii_whitespace()); /// assert!(!g.is_ascii_whitespace()); /// assert!(!zero.is_ascii_whitespace()); /// assert!(!percent.is_ascii_whitespace()); /// assert!(space.is_ascii_whitespace()); /// assert!(lf.is_ascii_whitespace()); /// assert!(!esc.is_ascii_whitespace()); /// ``` #[unstable(feature = "ascii_ctype", issue = "39658")] fn is_ascii_whitespace(&self) -> bool { unimplemented!(); } /// Checks if the value is an ASCII control character: /// U+0000 NUL ... U+001F UNIT SEPARATOR, or U+007F DELETE. /// Note that most ASCII whitespace characters are control /// characters, but SPACE is not. /// /// # Examples /// /// ``` /// #![feature(ascii_ctype)] /// # #![allow(non_snake_case)] /// use std::ascii::AsciiExt; /// let A = 'A'; /// let G = 'G'; /// let a = 'a'; /// let g = 'g'; /// let zero = '0'; /// let percent = '%'; /// let space = ' '; /// let lf = 'n'; /// let esc = 'u{001b}'; /// /// assert!(!A.is_ascii_control()); /// assert!(!G.is_ascii_control()); /// assert!(!a.is_ascii_control()); /// assert!(!g.is_ascii_control()); /// assert!(!zero.is_ascii_control()); /// assert!(!percent.is_ascii_control()); /// assert!(!space.is_ascii_control()); /// assert!(lf.is_ascii_control()); /// assert!(esc.is_ascii_control()); /// ``` #[unstable(feature = "ascii_ctype", issue = "39658")] fn is_ascii_control(&self) -> bool { unimplemented!(); } </ins> } #[stable(feature = "rust1", since = "1.0.0")]

let me: &mut [u8] = unsafe { mem::transmute(self) }; me.make_ascii_lowercase() } <ins> #[inline] fn is_ascii_alphabetic(&self) -> bool { self.bytes().all(|b| b.is_ascii_alphabetic()) } #[inline] fn is_ascii_uppercase(&self) -> bool { self.bytes().all(|b| b.is_ascii_uppercase()) } #[inline] fn is_ascii_lowercase(&self) -> bool { self.bytes().all(|b| b.is_ascii_lowercase()) } #[inline] fn is_ascii_alphanumeric(&self) -> bool { self.bytes().all(|b| b.is_ascii_alphanumeric()) } #[inline] fn is_ascii_digit(&self) -> bool { self.bytes().all(|b| b.is_ascii_digit()) } #[inline] fn is_ascii_hexdigit(&self) -> bool { self.bytes().all(|b| b.is_ascii_hexdigit()) } #[inline] fn is_ascii_punctuation(&self) -> bool { self.bytes().all(|b| b.is_ascii_punctuation()) } #[inline] fn is_ascii_graphic(&self) -> bool { self.bytes().all(|b| b.is_ascii_graphic()) } #[inline] fn is_ascii_whitespace(&self) -> bool { self.bytes().all(|b| b.is_ascii_whitespace()) } #[inline] fn is_ascii_control(&self) -> bool { self.bytes().all(|b| b.is_ascii_control()) } </ins> } #[stable(feature = "rust1", since = "1.0.0")]

byte.make_ascii_lowercase(); } } <ins> #[inline] fn is_ascii_alphabetic(&self) -> bool { self.iter().all(|b| b.is_ascii_alphabetic()) } #[inline] fn is_ascii_uppercase(&self) -> bool { self.iter().all(|b| b.is_ascii_uppercase()) } #[inline] fn is_ascii_lowercase(&self) -> bool { self.iter().all(|b| b.is_ascii_lowercase()) } #[inline] fn is_ascii_alphanumeric(&self) -> bool { self.iter().all(|b| b.is_ascii_alphanumeric()) } #[inline] fn is_ascii_digit(&self) -> bool { self.iter().all(|b| b.is_ascii_digit()) } #[inline] fn is_ascii_hexdigit(&self) -> bool { self.iter().all(|b| b.is_ascii_hexdigit()) } #[inline] fn is_ascii_punctuation(&self) -> bool { self.iter().all(|b| b.is_ascii_punctuation()) } #[inline] fn is_ascii_graphic(&self) -> bool { self.iter().all(|b| b.is_ascii_graphic()) } #[inline] fn is_ascii_whitespace(&self) -> bool { self.iter().all(|b| b.is_ascii_whitespace()) } #[inline] fn is_ascii_control(&self) -> bool { self.iter().all(|b| b.is_ascii_control()) } </ins> } #[stable(feature = "rust1", since = "1.0.0")]

fn make_ascii_uppercase(&mut self) { *self = self.to_ascii_uppercase(); } #[inline] fn make_ascii_lowercase(&mut self) { *self = self.to_ascii_lowercase(); } <ins> #[inline] fn is_ascii_alphabetic(&self) -> bool { if *self >= 0x80 { return false; } match ASCII_CHARACTER_CLASS[*self as usize] { L|Lx|U|Ux => true, _ => false } } #[inline] fn is_ascii_uppercase(&self) -> bool { if *self >= 0x80 { return false } match ASCII_CHARACTER_CLASS[*self as usize] { U|Ux => true, _ => false } } #[inline] fn is_ascii_lowercase(&self) -> bool { if *self >= 0x80 { return false } match ASCII_CHARACTER_CLASS[*self as usize] { L|Lx => true, _ => false } } #[inline] fn is_ascii_alphanumeric(&self) -> bool { if *self >= 0x80 { return false } match ASCII_CHARACTER_CLASS[*self as usize] { D|L|Lx|U|Ux => true, _ => false } } #[inline] fn is_ascii_digit(&self) -> bool { if *self >= 0x80 { return false } match ASCII_CHARACTER_CLASS[*self as usize] { D => true, _ => false } } #[inline] fn is_ascii_hexdigit(&self) -> bool { if *self >= 0x80 { return false } match ASCII_CHARACTER_CLASS[*self as usize] { D|Lx|Ux => true, _ => false } } #[inline] fn is_ascii_punctuation(&self) -> bool { if *self >= 0x80 { return false } match ASCII_CHARACTER_CLASS[*self as usize] { P => true, _ => false } } #[inline] fn is_ascii_graphic(&self) -> bool { if *self >= 0x80 { return false; } match ASCII_CHARACTER_CLASS[*self as usize] { Ux|U|Lx|L|D|P => true, _ => false } } #[inline] fn is_ascii_whitespace(&self) -> bool { if *self >= 0x80 { return false; } match ASCII_CHARACTER_CLASS[*self as usize] { Cw|W => true, _ => false } } #[inline] fn is_ascii_control(&self) -> bool { if *self >= 0x80 { return false; } match ASCII_CHARACTER_CLASS[*self as usize] { C|Cw => true, _ => false } } </ins> } #[stable(feature = "rust1", since = "1.0.0")]

fn make_ascii_uppercase(&mut self) { *self = self.to_ascii_uppercase(); } #[inline] fn make_ascii_lowercase(&mut self) { *self = self.to_ascii_lowercase(); } <ins> #[inline] fn is_ascii_alphabetic(&self) -> bool { (*self as u32 <= 0x7f) && (*self as u8).is_ascii_alphabetic() } #[inline] fn is_ascii_uppercase(&self) -> bool { (*self as u32 <= 0x7f) && (*self as u8).is_ascii_uppercase() } #[inline] fn is_ascii_lowercase(&self) -> bool { (*self as u32 <= 0x7f) && (*self as u8).is_ascii_lowercase() } #[inline] fn is_ascii_alphanumeric(&self) -> bool { (*self as u32 <= 0x7f) && (*self as u8).is_ascii_alphanumeric() } #[inline] fn is_ascii_digit(&self) -> bool { (*self as u32 <= 0x7f) && (*self as u8).is_ascii_digit() } #[inline] fn is_ascii_hexdigit(&self) -> bool { (*self as u32 <= 0x7f) && (*self as u8).is_ascii_hexdigit() } #[inline] fn is_ascii_punctuation(&self) -> bool { (*self as u32 <= 0x7f) && (*self as u8).is_ascii_punctuation() } #[inline] fn is_ascii_graphic(&self) -> bool { (*self as u32 <= 0x7f) && (*self as u8).is_ascii_graphic() } #[inline] fn is_ascii_whitespace(&self) -> bool { (*self as u32 <= 0x7f) && (*self as u8).is_ascii_whitespace() } #[inline] fn is_ascii_control(&self) -> bool { (*self as u32 <= 0x7f) && (*self as u8).is_ascii_control() } </ins> } /// An iterator over the escaped version of a byte, constructed via

0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, ]; <ins> enum AsciiCharacterClass { C,  // control Cw, // control whitespace W,  // whitespace D,  // digit L,  // lowercase Lx, // lowercase hex digit U,  // uppercase Ux, // uppercase hex digit P,  // punctuation } use self::AsciiCharacterClass::*; static ASCII_CHARACTER_CLASS: [AsciiCharacterClass; 128] = [ //  _0 _1 _2 _3 _4 _5 _6 _7 _8 _9 _a _b _c _d _e _f C, C, C, C, C, C, C, C, C, Cw,Cw,C, Cw,Cw,C, C, // 0_ C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, // 1_ W, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, // 2_ D, D, D, D, D, D, D, D, D, D, P, P, P, P, P, P, // 3_ P, Ux,Ux,Ux,Ux,Ux,Ux,U, U, U, U, U, U, U, U, U, // 4_ U, U, U, U, U, U, U, U, U, U, U, P, P, P, P, P, // 5_ P, Lx,Lx,Lx,Lx,Lx,Lx,L, L, L, L, L, L, L, L, L, // 6_ L, L, L, L, L, L, L, L, L, L, L, P, P, P, P, C, // 7_ ]; </ins> #[cfg(test)] mod tests {

let x = "a".to_string(); x.eq_ignore_ascii_case("A"); } <ins> // Shorthands used by the is_ascii_* tests. macro_rules! assert_all { ($what:ident, $($str:tt),+) => {{ $( for b in $str.chars() { if !b.$what() { panic!("expected {}({}) but it isn't", stringify!($what), b); } } for b in $str.as_bytes().iter() { if !b.$what() { panic!("expected {}(0x{:02x})) but it isn't", stringify!($what), b); } } assert!($str.$what()); assert!($str.as_bytes().$what()); )+ }}; ($what:ident, $($str:tt),+,) => (assert_all!($what,$($str),+)) } macro_rules! assert_none { ($what:ident, $($str:tt),+) => {{ $( for b in $str.chars() { if b.$what() { panic!("expected not-{}({}) but it is", stringify!($what), b); } } for b in $str.as_bytes().iter() { if b.$what() { panic!("expected not-{}(0x{:02x})) but it is", stringify!($what), b); } } )* }}; ($what:ident, $($str:tt),+,) => (assert_none!($what,$($str),+)) } #[test] fn test_is_ascii_alphabetic() { assert_all!(is_ascii_alphabetic, "", "abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOQPRSTUVWXYZ", ); assert_none!(is_ascii_alphabetic, "0123456789", "!"#$%&'()*+,-./:;<=>?@[]^_`{|}~", " tnx0cr", "x00x01x02x03x04x05x06x07", "x08x09x0ax0bx0cx0dx0ex0f", "x10x11x12x13x14x15x16x17", "x18x19x1ax1bx1cx1dx1ex1f", "x7f", ); } #[test] fn test_is_ascii_uppercase() { assert_all!(is_ascii_uppercase, "", "ABCDEFGHIJKLMNOQPRSTUVWXYZ", ); assert_none!(is_ascii_uppercase, "abcdefghijklmnopqrstuvwxyz", "0123456789", "!"#$%&'()*+,-./:;<=>?@[]^_`{|}~", " tnx0cr", "x00x01x02x03x04x05x06x07", "x08x09x0ax0bx0cx0dx0ex0f", "x10x11x12x13x14x15x16x17", "x18x19x1ax1bx1cx1dx1ex1f", "x7f", ); } #[test] fn test_is_ascii_lowercase() { assert_all!(is_ascii_lowercase, "abcdefghijklmnopqrstuvwxyz", ); assert_none!(is_ascii_lowercase, "ABCDEFGHIJKLMNOQPRSTUVWXYZ", "0123456789", "!"#$%&'()*+,-./:;<=>?@[]^_`{|}~", " tnx0cr", "x00x01x02x03x04x05x06x07", "x08x09x0ax0bx0cx0dx0ex0f", "x10x11x12x13x14x15x16x17", "x18x19x1ax1bx1cx1dx1ex1f", "x7f", ); } #[test] fn test_is_ascii_alphanumeric() { assert_all!(is_ascii_alphanumeric, "", "abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOQPRSTUVWXYZ", "0123456789", ); assert_none!(is_ascii_alphanumeric, "!"#$%&'()*+,-./:;<=>?@[]^_`{|}~", " tnx0cr", "x00x01x02x03x04x05x06x07", "x08x09x0ax0bx0cx0dx0ex0f", "x10x11x12x13x14x15x16x17", "x18x19x1ax1bx1cx1dx1ex1f", "x7f", ); } #[test] fn test_is_ascii_digit() { assert_all!(is_ascii_digit, "", "0123456789", ); assert_none!(is_ascii_digit, "abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOQPRSTUVWXYZ", "!"#$%&'()*+,-./:;<=>?@[]^_`{|}~", " tnx0cr", "x00x01x02x03x04x05x06x07", "x08x09x0ax0bx0cx0dx0ex0f", "x10x11x12x13x14x15x16x17", "x18x19x1ax1bx1cx1dx1ex1f", "x7f", ); } #[test] fn test_is_ascii_hexdigit() { assert_all!(is_ascii_hexdigit, "", "0123456789", "abcdefABCDEF", ); assert_none!(is_ascii_hexdigit, "ghijklmnopqrstuvwxyz", "GHIJKLMNOQPRSTUVWXYZ", "!"#$%&'()*+,-./:;<=>?@[]^_`{|}~", " tnx0cr", "x00x01x02x03x04x05x06x07", "x08x09x0ax0bx0cx0dx0ex0f", "x10x11x12x13x14x15x16x17", "x18x19x1ax1bx1cx1dx1ex1f", "x7f", ); } #[test] fn test_is_ascii_punctuation() { assert_all!(is_ascii_punctuation, "", "!"#$%&'()*+,-./:;<=>?@[]^_`{|}~", ); assert_none!(is_ascii_punctuation, "abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOQPRSTUVWXYZ", "0123456789", " tnx0cr", "x00x01x02x03x04x05x06x07", "x08x09x0ax0bx0cx0dx0ex0f", "x10x11x12x13x14x15x16x17", "x18x19x1ax1bx1cx1dx1ex1f", "x7f", ); } #[test] fn test_is_ascii_graphic() { assert_all!(is_ascii_graphic, "", "abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOQPRSTUVWXYZ", "0123456789", "!"#$%&'()*+,-./:;<=>?@[]^_`{|}~", ); assert_none!(is_ascii_graphic, " tnx0cr", "x00x01x02x03x04x05x06x07", "x08x09x0ax0bx0cx0dx0ex0f", "x10x11x12x13x14x15x16x17", "x18x19x1ax1bx1cx1dx1ex1f", "x7f", ); } #[test] fn test_is_ascii_whitespace() { assert_all!(is_ascii_whitespace, "", " tnx0cr", ); assert_none!(is_ascii_whitespace, "abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOQPRSTUVWXYZ", "0123456789", "!"#$%&'()*+,-./:;<=>?@[]^_`{|}~", "x00x01x02x03x04x05x06x07", "x08x0bx0ex0f", "x10x11x12x13x14x15x16x17", "x18x19x1ax1bx1cx1dx1ex1f", "x7f", ); } #[test] fn test_is_ascii_control() { assert_all!(is_ascii_control, "", "x00x01x02x03x04x05x06x07", "x08x09x0ax0bx0cx0dx0ex0f", "x10x11x12x13x14x15x16x17", "x18x19x1ax1bx1cx1dx1ex1f", "x7f", ); assert_none!(is_ascii_control, "abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOQPRSTUVWXYZ", "0123456789", "!"#$%&'()*+,-./:;<=>?@[]^_`{|}~", " ", ); } </ins> }