1 #![cfg_attr(rustfmt, rustfmt_skip)] 2 3 // #[allow(deprecated)] doesn't silence warnings on the method invocations, 4 // which would call the inherent methods if AsciiExt wasn't in scope. 5 #![cfg_attr(feature = "std", allow(deprecated))] 6 7 #[cfg(feature = "quickcheck")] 8 use quickcheck::{Arbitrary, Gen}; 9 10 use core::mem; 11 use core::cmp::Ordering; 12 use core::{fmt, char}; 13 #[cfg(feature = "std")] 14 use std::error::Error; 15 #[cfg(feature = "std")] 16 use std::ascii::AsciiExt; 17 18 #[allow(non_camel_case_types)] 19 /// An ASCII character. It wraps a `u8`, with the highest bit always zero. 20 #[derive(Clone, PartialEq, PartialOrd, Ord, Eq, Hash, Copy)] 21 #[repr(u8)] 22 pub enum AsciiChar { 23 /// `'\0'` 24 Null = 0, 25 /// [Start Of Heading](http://en.wikipedia.org/wiki/Start_of_Heading) 26 SOH = 1, 27 /// [Start Of teXt](http://en.wikipedia.org/wiki/Start_of_Text) 28 SOX = 2, 29 /// [End of TeXt](http://en.wikipedia.org/wiki/End-of-Text_character) 30 ETX = 3, 31 /// [End Of Transmission](http://en.wikipedia.org/wiki/End-of-Transmission_character) 32 EOT = 4, 33 /// [Enquiry](http://en.wikipedia.org/wiki/Enquiry_character) 34 ENQ = 5, 35 /// [Acknowledgement](http://en.wikipedia.org/wiki/Acknowledge_character) 36 ACK = 6, 37 /// [bell / alarm / audible](http://en.wikipedia.org/wiki/Bell_character) 38 /// 39 /// `'\a'` is not recognized by Rust. 40 Bell = 7, 41 /// [Backspace](http://en.wikipedia.org/wiki/Backspace) 42 /// 43 /// `'\b'` is not recognized by Rust. 44 BackSpace = 8, 45 /// `'\t'` 46 Tab = 9, 47 /// `'\n'` 48 LineFeed = 10, 49 /// [Vertical tab](http://en.wikipedia.org/wiki/Vertical_Tab) 50 /// 51 /// `'\v'` is not recognized by Rust. 52 VT = 11, 53 /// [Form Feed](http://en.wikipedia.org/wiki/Form_Feed) 54 /// 55 /// `'\f'` is not recognized by Rust. 56 FF = 12, 57 /// `'\r'` 58 CarriageReturn = 13, 59 /// [Shift In](http://en.wikipedia.org/wiki/Shift_Out_and_Shift_In_characters) 60 SI = 14, 61 /// [Shift Out](http://en.wikipedia.org/wiki/Shift_Out_and_Shift_In_characters) 62 SO = 15, 63 /// [Data Link Escape](http://en.wikipedia.org/wiki/Data_Link_Escape) 64 DLE = 16, 65 /// [Device control 1, often XON](http://en.wikipedia.org/wiki/Device_Control_1) 66 DC1 = 17, 67 /// Device control 2 68 DC2 = 18, 69 /// Device control 3, Often XOFF 70 DC3 = 19, 71 /// Device control 4 72 DC4 = 20, 73 /// [Negative AcKnowledgement](http://en.wikipedia.org/wiki/Negative-acknowledge_character) 74 NAK = 21, 75 /// [Synchronous idle](http://en.wikipedia.org/wiki/Synchronous_Idle) 76 SYN = 22, 77 /// [End of Transmission Block](http://en.wikipedia.org/wiki/End-of-Transmission-Block_character) 78 ETB = 23, 79 /// [Cancel](http://en.wikipedia.org/wiki/Cancel_character) 80 CAN = 24, 81 /// [End of Medium](http://en.wikipedia.org/wiki/End_of_Medium) 82 EM = 25, 83 /// [Substitute](http://en.wikipedia.org/wiki/Substitute_character) 84 SUB = 26, 85 /// [Escape](http://en.wikipedia.org/wiki/Escape_character) 86 /// 87 /// `'\e'` is not recognized by Rust. 88 ESC = 27, 89 /// [File Separator](http://en.wikipedia.org/wiki/File_separator) 90 FS = 28, 91 /// [Group Separator](http://en.wikipedia.org/wiki/Group_separator) 92 GS = 29, 93 /// [Record Separator](http://en.wikipedia.org/wiki/Record_separator) 94 RS = 30, 95 /// [Unit Separator](http://en.wikipedia.org/wiki/Unit_separator) 96 US = 31, 97 /// `' '` 98 Space = 32, 99 /// `'!'` 100 Exclamation = 33, 101 /// `'"'` 102 Quotation = 34, 103 /// `'#'` 104 Hash = 35, 105 /// `'$'` 106 Dollar = 36, 107 /// `'%'` 108 Percent = 37, 109 /// `'&'` 110 Ampersand = 38, 111 /// `'\''` 112 Apostrophe = 39, 113 /// `'('` 114 ParenOpen = 40, 115 /// `')'` 116 ParenClose = 41, 117 /// `'*'` 118 Asterisk = 42, 119 /// `'+'` 120 Plus = 43, 121 /// `','` 122 Comma = 44, 123 /// `'-'` 124 Minus = 45, 125 /// `'.'` 126 Dot = 46, 127 /// `'/'` 128 Slash = 47, 129 /// `'0'` 130 _0 = 48, 131 /// `'1'` 132 _1 = 49, 133 /// `'2'` 134 _2 = 50, 135 /// `'3'` 136 _3 = 51, 137 /// `'4'` 138 _4 = 52, 139 /// `'5'` 140 _5 = 53, 141 /// `'6'` 142 _6 = 54, 143 /// `'7'` 144 _7 = 55, 145 /// `'8'` 146 _8 = 56, 147 /// `'9'` 148 _9 = 57, 149 /// `':'` 150 Colon = 58, 151 /// `';'` 152 Semicolon = 59, 153 /// `'<'` 154 LessThan = 60, 155 /// `'='` 156 Equal = 61, 157 /// `'>'` 158 GreaterThan = 62, 159 /// `'?'` 160 Question = 63, 161 /// `'@'` 162 At = 64, 163 /// `'A'` 164 A = 65, 165 /// `'B'` 166 B = 66, 167 /// `'C'` 168 C = 67, 169 /// `'D'` 170 D = 68, 171 /// `'E'` 172 E = 69, 173 /// `'F'` 174 F = 70, 175 /// `'G'` 176 G = 71, 177 /// `'H'` 178 H = 72, 179 /// `'I'` 180 I = 73, 181 /// `'J'` 182 J = 74, 183 /// `'K'` 184 K = 75, 185 /// `'L'` 186 L = 76, 187 /// `'M'` 188 M = 77, 189 /// `'N'` 190 N = 78, 191 /// `'O'` 192 O = 79, 193 /// `'P'` 194 P = 80, 195 /// `'Q'` 196 Q = 81, 197 /// `'R'` 198 R = 82, 199 /// `'S'` 200 S = 83, 201 /// `'T'` 202 T = 84, 203 /// `'U'` 204 U = 85, 205 /// `'V'` 206 V = 86, 207 /// `'W'` 208 W = 87, 209 /// `'X'` 210 X = 88, 211 /// `'Y'` 212 Y = 89, 213 /// `'Z'` 214 Z = 90, 215 /// `'['` 216 BracketOpen = 91, 217 /// `'\'` 218 BackSlash = 92, 219 /// `']'` 220 BracketClose = 93, 221 /// `'_'` 222 Caret = 94, 223 /// `'_'` 224 UnderScore = 95, 225 /// `'`'` 226 Grave = 96, 227 /// `'a'` 228 a = 97, 229 /// `'b'` 230 b = 98, 231 /// `'c'` 232 c = 99, 233 /// `'d'` 234 d = 100, 235 /// `'e'` 236 e = 101, 237 /// `'f'` 238 f = 102, 239 /// `'g'` 240 g = 103, 241 /// `'h'` 242 h = 104, 243 /// `'i'` 244 i = 105, 245 /// `'j'` 246 j = 106, 247 /// `'k'` 248 k = 107, 249 /// `'l'` 250 l = 108, 251 /// `'m'` 252 m = 109, 253 /// `'n'` 254 n = 110, 255 /// `'o'` 256 o = 111, 257 /// `'p'` 258 p = 112, 259 /// `'q'` 260 q = 113, 261 /// `'r'` 262 r = 114, 263 /// `'s'` 264 s = 115, 265 /// `'t'` 266 t = 116, 267 /// `'u'` 268 u = 117, 269 /// `'v'` 270 v = 118, 271 /// `'w'` 272 w = 119, 273 /// `'x'` 274 x = 120, 275 /// `'y'` 276 y = 121, 277 /// `'z'` 278 z = 122, 279 /// `'{'` 280 CurlyBraceOpen = 123, 281 /// `'|'` 282 VerticalBar = 124, 283 /// `'}'` 284 CurlyBraceClose = 125, 285 /// `'~'` 286 Tilde = 126, 287 /// [Delete](http://en.wikipedia.org/wiki/Delete_character) 288 DEL = 127, 289 } 290 291 impl AsciiChar { 292 /// Constructs an ASCII character from a `u8`, `char` or other character type. 293 /// 294 /// # Failure 295 /// Returns `Err(())` if the character can't be ASCII encoded. 296 /// 297 /// # Example 298 /// ``` 299 /// # use ascii::AsciiChar; 300 /// let a = AsciiChar::from('g').unwrap(); 301 /// assert_eq!(a.as_char(), 'g'); 302 /// ``` 303 #[inline] from<C: ToAsciiChar>(ch: C) -> Result<Self, ToAsciiCharError>304 pub fn from<C: ToAsciiChar>(ch: C) -> Result<Self, ToAsciiCharError> { 305 ch.to_ascii_char() 306 } 307 308 /// Constructs an ASCII character from a `char` or `u8` without any checks. 309 #[inline] from_unchecked<C: ToAsciiChar>(ch: C) -> Self310 pub unsafe fn from_unchecked<C: ToAsciiChar>(ch: C) -> Self { 311 ch.to_ascii_char_unchecked() 312 } 313 314 /// Converts an ASCII character into a `u8`. 315 #[inline] as_byte(self) -> u8316 pub fn as_byte(self) -> u8 { 317 self as u8 318 } 319 320 /// Converts an ASCII character into a `char`. 321 #[inline] as_char(self) -> char322 pub fn as_char(self) -> char { 323 self.as_byte() as char 324 } 325 326 // the following methods are like ctype, and the implementation is inspired by musl 327 328 /// Check if the character is a letter (a-z, A-Z) 329 #[inline] is_alphabetic(self) -> bool330 pub fn is_alphabetic(self) -> bool { 331 let c = self.as_byte() | 0b010_0000; // Turns uppercase into lowercase. 332 c >= b'a' && c <= b'z' 333 } 334 335 /// Check if the character is a number (0-9) 336 #[inline] is_digit(self) -> bool337 pub fn is_digit(self) -> bool { 338 self >= AsciiChar::_0 && self <= AsciiChar::_9 339 } 340 341 /// Check if the character is a letter or number 342 #[inline] is_alphanumeric(self) -> bool343 pub fn is_alphanumeric(self) -> bool { 344 self.is_alphabetic() || self.is_digit() 345 } 346 347 /// Check if the character is a space or horizontal tab 348 #[inline] is_blank(self) -> bool349 pub fn is_blank(self) -> bool { 350 self == AsciiChar::Space || self == AsciiChar::Tab 351 } 352 353 /// Check if the character is a ' ', '\t', '\n' or '\r' 354 #[inline] is_whitespace(self) -> bool355 pub fn is_whitespace(self) -> bool { 356 self.is_blank() || self == AsciiChar::LineFeed || self == AsciiChar::CarriageReturn 357 } 358 359 /// Check if the character is a control character 360 /// 361 /// # Examples 362 /// ``` 363 /// use ascii::ToAsciiChar; 364 /// assert_eq!('\0'.to_ascii_char().unwrap().is_control(), true); 365 /// assert_eq!('n'.to_ascii_char().unwrap().is_control(), false); 366 /// assert_eq!(' '.to_ascii_char().unwrap().is_control(), false); 367 /// assert_eq!('\n'.to_ascii_char().unwrap().is_control(), true); 368 /// ``` 369 #[inline] is_control(self) -> bool370 pub fn is_control(self) -> bool { 371 self < AsciiChar::Space || self == AsciiChar::DEL 372 } 373 374 /// Checks if the character is printable (except space) 375 /// 376 /// # Examples 377 /// ``` 378 /// use ascii::ToAsciiChar; 379 /// assert_eq!('n'.to_ascii_char().unwrap().is_graph(), true); 380 /// assert_eq!(' '.to_ascii_char().unwrap().is_graph(), false); 381 /// assert_eq!('\n'.to_ascii_char().unwrap().is_graph(), false); 382 /// ``` 383 #[inline] is_graph(self) -> bool384 pub fn is_graph(self) -> bool { 385 self.as_byte().wrapping_sub(b' ' + 1) < 0x5E 386 } 387 388 /// Checks if the character is printable (including space) 389 /// 390 /// # Examples 391 /// ``` 392 /// use ascii::ToAsciiChar; 393 /// assert_eq!('n'.to_ascii_char().unwrap().is_print(), true); 394 /// assert_eq!(' '.to_ascii_char().unwrap().is_print(), true); 395 /// assert_eq!('\n'.to_ascii_char().unwrap().is_print(), false); 396 /// ``` 397 #[inline] is_print(self) -> bool398 pub fn is_print(self) -> bool { 399 self.as_byte().wrapping_sub(b' ') < 0x5F 400 } 401 402 /// Checks if the character is alphabetic and lowercase 403 /// 404 /// # Examples 405 /// ``` 406 /// use ascii::ToAsciiChar; 407 /// assert_eq!('a'.to_ascii_char().unwrap().is_lowercase(), true); 408 /// assert_eq!('A'.to_ascii_char().unwrap().is_lowercase(), false); 409 /// assert_eq!('@'.to_ascii_char().unwrap().is_lowercase(), false); 410 /// ``` 411 #[inline] is_lowercase(self) -> bool412 pub fn is_lowercase(self) -> bool { 413 self.as_byte().wrapping_sub(b'a') < 26 414 } 415 416 /// Checks if the character is alphabetic and uppercase 417 /// 418 /// # Examples 419 /// ``` 420 /// use ascii::ToAsciiChar; 421 /// assert_eq!('A'.to_ascii_char().unwrap().is_uppercase(), true); 422 /// assert_eq!('a'.to_ascii_char().unwrap().is_uppercase(), false); 423 /// assert_eq!('@'.to_ascii_char().unwrap().is_uppercase(), false); 424 /// ``` 425 #[inline] is_uppercase(self) -> bool426 pub fn is_uppercase(self) -> bool { 427 self.as_byte().wrapping_sub(b'A') < 26 428 } 429 430 /// Checks if the character is punctuation 431 /// 432 /// # Examples 433 /// ``` 434 /// use ascii::ToAsciiChar; 435 /// assert_eq!('n'.to_ascii_char().unwrap().is_punctuation(), false); 436 /// assert_eq!(' '.to_ascii_char().unwrap().is_punctuation(), false); 437 /// assert_eq!('_'.to_ascii_char().unwrap().is_punctuation(), true); 438 /// assert_eq!('~'.to_ascii_char().unwrap().is_punctuation(), true); 439 /// ``` 440 #[inline] is_punctuation(self) -> bool441 pub fn is_punctuation(self) -> bool { 442 self.is_graph() && !self.is_alphanumeric() 443 } 444 445 /// Checks if the character is a valid hex digit 446 /// 447 /// # Examples 448 /// ``` 449 /// use ascii::ToAsciiChar; 450 /// assert_eq!('5'.to_ascii_char().unwrap().is_hex(), true); 451 /// assert_eq!('a'.to_ascii_char().unwrap().is_hex(), true); 452 /// assert_eq!('F'.to_ascii_char().unwrap().is_hex(), true); 453 /// assert_eq!('G'.to_ascii_char().unwrap().is_hex(), false); 454 /// assert_eq!(' '.to_ascii_char().unwrap().is_hex(), false); 455 /// ``` 456 #[inline] is_hex(self) -> bool457 pub fn is_hex(self) -> bool { 458 self.is_digit() || (self.as_byte() | 0x20u8).wrapping_sub(b'a') < 6 459 } 460 461 /// Unicode has printable versions of the ASCII control codes, like '␛'. 462 /// 463 /// This function is identical with `.as_char()` 464 /// for all values `.is_printable()` returns true for, 465 /// but replaces the control codes with those unicodes printable versions. 466 /// 467 /// # Examples 468 /// ``` 469 /// # use ascii::ToAsciiChar; 470 /// assert_eq!('\0'.to_ascii_char().unwrap().as_printable_char(), '␀'); 471 /// assert_eq!('\n'.to_ascii_char().unwrap().as_printable_char(), '␊'); 472 /// assert_eq!(' '.to_ascii_char().unwrap().as_printable_char(), ' '); 473 /// assert_eq!('p'.to_ascii_char().unwrap().as_printable_char(), 'p'); 474 /// ``` as_printable_char(self) -> char475 pub fn as_printable_char(self) -> char { 476 unsafe { 477 match self as u8 { 478 b' '...b'~' => self.as_char(), 479 127 => '␡', 480 _ => char::from_u32_unchecked(self as u32 + '␀' as u32), 481 } 482 } 483 } 484 485 /// Replaces letters `a` to `z` with `A` to `Z` make_ascii_uppercase(&mut self)486 pub fn make_ascii_uppercase(&mut self) { 487 *self = self.to_ascii_uppercase() 488 } 489 490 /// Replaces letters `A` to `Z` with `a` to `z` make_ascii_lowercase(&mut self)491 pub fn make_ascii_lowercase(&mut self) { 492 *self = self.to_ascii_lowercase() 493 } 494 495 /// Maps letters `a`...`z` to `A`...`Z` and returns everything else unchanged. 496 #[inline] to_ascii_uppercase(&self) -> Self497 pub fn to_ascii_uppercase(&self) -> Self { 498 unsafe { 499 match *self as u8 { 500 b'a'...b'z' => AsciiChar::from_unchecked(self.as_byte() - (b'a' - b'A')), 501 _ => *self, 502 } 503 } 504 } 505 506 /// Maps letters `A`...`Z` to `a`...`z` and returns everything else unchanged. 507 #[inline] to_ascii_lowercase(&self) -> Self508 pub fn to_ascii_lowercase(&self) -> Self { 509 unsafe { 510 match *self as u8 { 511 b'A'...b'Z' => AsciiChar::from_unchecked(self.as_byte() + (b'a' - b'A')), 512 _ => *self, 513 } 514 } 515 } 516 517 /// Compares two characters case-insensitively. eq_ignore_ascii_case(&self, other: &Self) -> bool518 pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool { 519 self.to_ascii_lowercase() == other.to_ascii_lowercase() 520 } 521 } 522 523 impl fmt::Display for AsciiChar { 524 #[inline] fmt(&self, f: &mut fmt::Formatter) -> fmt::Result525 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 526 self.as_char().fmt(f) 527 } 528 } 529 530 impl fmt::Debug for AsciiChar { 531 #[inline] fmt(&self, f: &mut fmt::Formatter) -> fmt::Result532 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 533 self.as_char().fmt(f) 534 } 535 } 536 537 #[cfg(feature = "std")] 538 impl AsciiExt for AsciiChar { 539 type Owned = AsciiChar; 540 541 #[inline] is_ascii(&self) -> bool542 fn is_ascii(&self) -> bool { 543 true 544 } 545 546 #[inline] to_ascii_uppercase(&self) -> AsciiChar547 fn to_ascii_uppercase(&self) -> AsciiChar { 548 unsafe { 549 self.as_byte() 550 .to_ascii_uppercase() 551 .to_ascii_char_unchecked() 552 } 553 } 554 555 #[inline] to_ascii_lowercase(&self) -> AsciiChar556 fn to_ascii_lowercase(&self) -> AsciiChar { 557 unsafe { 558 self.as_byte() 559 .to_ascii_lowercase() 560 .to_ascii_char_unchecked() 561 } 562 } 563 eq_ignore_ascii_case(&self, other: &Self) -> bool564 fn eq_ignore_ascii_case(&self, other: &Self) -> bool { 565 self.as_byte().eq_ignore_ascii_case(&other.as_byte()) 566 } 567 568 #[inline] make_ascii_uppercase(&mut self)569 fn make_ascii_uppercase(&mut self) { 570 *self = self.to_ascii_uppercase(); 571 } 572 573 #[inline] make_ascii_lowercase(&mut self)574 fn make_ascii_lowercase(&mut self) { 575 *self = self.to_ascii_lowercase(); 576 } 577 } 578 579 impl Default for AsciiChar { default() -> AsciiChar580 fn default() -> AsciiChar { 581 AsciiChar::Null 582 } 583 } 584 585 macro_rules! impl_into_partial_eq_ord {($wider:ty, $to_wider:expr) => { 586 impl From<AsciiChar> for $wider { 587 #[inline] 588 fn from(a: AsciiChar) -> $wider { 589 $to_wider(a) 590 } 591 } 592 impl PartialEq<$wider> for AsciiChar { 593 #[inline] 594 fn eq(&self, rhs: &$wider) -> bool { 595 $to_wider(*self) == *rhs 596 } 597 } 598 impl PartialEq<AsciiChar> for $wider { 599 #[inline] 600 fn eq(&self, rhs: &AsciiChar) -> bool { 601 *self == $to_wider(*rhs) 602 } 603 } 604 impl PartialOrd<$wider> for AsciiChar { 605 #[inline] 606 fn partial_cmp(&self, rhs: &$wider) -> Option<Ordering> { 607 $to_wider(*self).partial_cmp(rhs) 608 } 609 } 610 impl PartialOrd<AsciiChar> for $wider { 611 #[inline] 612 fn partial_cmp(&self, rhs: &AsciiChar) -> Option<Ordering> { 613 self.partial_cmp(&$to_wider(*rhs)) 614 } 615 } 616 }} 617 impl_into_partial_eq_ord!{u8, AsciiChar::as_byte} 618 impl_into_partial_eq_ord!{char, AsciiChar::as_char} 619 620 621 /// Error returned by `ToAsciiChar`. 622 #[derive(Clone, Copy, PartialEq, Eq)] 623 pub struct ToAsciiCharError(()); 624 625 const ERRORMSG_CHAR: &'static str = "not an ASCII character"; 626 627 #[cfg(not(feature = "std"))] 628 impl ToAsciiCharError { 629 /// Returns a description for this error, like `std::error::Error::description`. 630 #[inline] description(&self) -> &'static str631 pub fn description(&self) -> &'static str { 632 ERRORMSG_CHAR 633 } 634 } 635 636 impl fmt::Debug for ToAsciiCharError { fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result637 fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result { 638 write!(fmtr, "{}", ERRORMSG_CHAR) 639 } 640 } 641 642 impl fmt::Display for ToAsciiCharError { fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result643 fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result { 644 write!(fmtr, "{}", ERRORMSG_CHAR) 645 } 646 } 647 648 #[cfg(feature = "std")] 649 impl Error for ToAsciiCharError { 650 #[inline] description(&self) -> &'static str651 fn description(&self) -> &'static str { 652 ERRORMSG_CHAR 653 } 654 } 655 656 /// Convert `char`, `u8` and other character types to `AsciiChar`. 657 pub trait ToAsciiChar { 658 /// Convert to `AsciiChar` without checking that it is an ASCII character. to_ascii_char_unchecked(self) -> AsciiChar659 unsafe fn to_ascii_char_unchecked(self) -> AsciiChar; 660 /// Convert to `AsciiChar`. to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError>661 fn to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError>; 662 } 663 664 impl ToAsciiChar for AsciiChar { 665 #[inline] to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError>666 fn to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError> { 667 Ok(self) 668 } 669 #[inline] to_ascii_char_unchecked(self) -> AsciiChar670 unsafe fn to_ascii_char_unchecked(self) -> AsciiChar { 671 self 672 } 673 } 674 675 impl ToAsciiChar for u8 { 676 #[inline] to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError>677 fn to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError> { 678 (self as u32).to_ascii_char() 679 } 680 #[inline] to_ascii_char_unchecked(self) -> AsciiChar681 unsafe fn to_ascii_char_unchecked(self) -> AsciiChar { 682 mem::transmute(self) 683 } 684 } 685 686 impl ToAsciiChar for i8 { 687 #[inline] to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError>688 fn to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError> { 689 (self as u32).to_ascii_char() 690 } 691 #[inline] to_ascii_char_unchecked(self) -> AsciiChar692 unsafe fn to_ascii_char_unchecked(self) -> AsciiChar { 693 mem::transmute(self) 694 } 695 } 696 697 impl ToAsciiChar for char { 698 #[inline] to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError>699 fn to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError> { 700 (self as u32).to_ascii_char() 701 } 702 #[inline] to_ascii_char_unchecked(self) -> AsciiChar703 unsafe fn to_ascii_char_unchecked(self) -> AsciiChar { 704 (self as u32).to_ascii_char_unchecked() 705 } 706 } 707 708 impl ToAsciiChar for u32 { to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError>709 fn to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError> { 710 unsafe { 711 match self { 712 0..=127 => Ok(self.to_ascii_char_unchecked()), 713 _ => Err(ToAsciiCharError(())) 714 } 715 } 716 } 717 #[inline] to_ascii_char_unchecked(self) -> AsciiChar718 unsafe fn to_ascii_char_unchecked(self) -> AsciiChar { 719 (self as u8).to_ascii_char_unchecked() 720 } 721 } 722 723 impl ToAsciiChar for u16 { to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError>724 fn to_ascii_char(self) -> Result<AsciiChar, ToAsciiCharError> { 725 (self as u32).to_ascii_char() 726 } 727 #[inline] to_ascii_char_unchecked(self) -> AsciiChar728 unsafe fn to_ascii_char_unchecked(self) -> AsciiChar { 729 (self as u8).to_ascii_char_unchecked() 730 } 731 } 732 733 #[cfg(feature = "quickcheck")] 734 impl Arbitrary for AsciiChar { arbitrary<G: Gen>(g: &mut G) -> Self735 fn arbitrary<G: Gen>(g: &mut G) -> Self { 736 let mode = g.gen_range(0, 100); 737 match mode { 738 0...14 => { 739 // Control characters 740 unsafe { AsciiChar::from_unchecked(g.gen_range(0, 0x1F) as u8) } 741 } 742 15...39 => { 743 // Characters often used in programming languages 744 *g.choose(&[ 745 AsciiChar::Space, AsciiChar::Tab, AsciiChar::LineFeed, AsciiChar::Tilde, 746 AsciiChar::Grave, AsciiChar::Exclamation, AsciiChar::At, AsciiChar::Hash, 747 AsciiChar::Dollar, AsciiChar::Percent, AsciiChar::Ampersand, 748 AsciiChar::Asterisk, AsciiChar::ParenOpen, AsciiChar::ParenClose, 749 AsciiChar::UnderScore, AsciiChar::Minus, AsciiChar::Equal, AsciiChar::Plus, 750 AsciiChar::BracketOpen, AsciiChar::BracketClose, AsciiChar::CurlyBraceOpen, 751 AsciiChar::CurlyBraceClose, AsciiChar::Colon, AsciiChar::Semicolon, 752 AsciiChar::Apostrophe, AsciiChar::Quotation, AsciiChar::BackSlash, 753 AsciiChar::VerticalBar, AsciiChar::Caret, AsciiChar::Comma, AsciiChar::LessThan, 754 AsciiChar::GreaterThan, AsciiChar::Dot, AsciiChar::Slash, AsciiChar::Question, 755 AsciiChar::_0, AsciiChar::_1, AsciiChar::_2, AsciiChar::_3, AsciiChar::_3, 756 AsciiChar::_4 , AsciiChar::_6, AsciiChar::_7, AsciiChar::_8, AsciiChar::_9, 757 ]).unwrap() 758 } 759 40...99 => { 760 // Completely arbitrary characters 761 unsafe { AsciiChar::from_unchecked(g.gen_range(0, 0x80) as u8) } 762 } 763 _ => unreachable!(), 764 } 765 } 766 shrink(&self) -> Box<Iterator<Item = Self>>767 fn shrink(&self) -> Box<Iterator<Item = Self>> { 768 Box::new((*self as u8).shrink().filter_map( 769 |x| AsciiChar::from(x).ok(), 770 )) 771 } 772 } 773 774 #[cfg(test)] 775 mod tests { 776 use super::{AsciiChar, ToAsciiChar, ToAsciiCharError}; 777 use AsciiChar::*; 778 779 #[test] to_ascii_char()780 fn to_ascii_char() { 781 fn generic<C: ToAsciiChar>(ch: C) -> Result<AsciiChar, ToAsciiCharError> { 782 ch.to_ascii_char() 783 } 784 assert_eq!(generic(A), Ok(A)); 785 assert_eq!(generic(b'A'), Ok(A)); 786 assert_eq!(generic('A'), Ok(A)); 787 assert!(generic(200u16).is_err()); 788 assert!(generic('λ').is_err()); 789 } 790 791 #[test] as_byte_and_char()792 fn as_byte_and_char() { 793 assert_eq!(A.as_byte(), b'A'); 794 assert_eq!(A.as_char(), 'A'); 795 } 796 797 #[test] is_digit()798 fn is_digit() { 799 assert_eq!('0'.to_ascii_char().unwrap().is_digit(), true); 800 assert_eq!('9'.to_ascii_char().unwrap().is_digit(), true); 801 assert_eq!('/'.to_ascii_char().unwrap().is_digit(), false); 802 assert_eq!(':'.to_ascii_char().unwrap().is_digit(), false); 803 } 804 805 #[test] is_control()806 fn is_control() { 807 assert_eq!(US.is_control(), true); 808 assert_eq!(DEL.is_control(), true); 809 assert_eq!(Space.is_control(), false); 810 } 811 812 #[test] cmp_wider()813 fn cmp_wider() { 814 assert_eq!(A, 'A'); 815 assert_eq!(b'b', b); 816 assert!(a < 'z'); 817 } 818 819 #[test] ascii_case()820 fn ascii_case() { 821 assert_eq!(At.to_ascii_lowercase(), At); 822 assert_eq!(At.to_ascii_uppercase(), At); 823 assert_eq!(A.to_ascii_lowercase(), a); 824 assert_eq!(A.to_ascii_uppercase(), A); 825 assert_eq!(a.to_ascii_lowercase(), a); 826 assert_eq!(a.to_ascii_uppercase(), A); 827 828 assert!(LineFeed.eq_ignore_ascii_case(&LineFeed)); 829 assert!(!LineFeed.eq_ignore_ascii_case(&CarriageReturn)); 830 assert!(z.eq_ignore_ascii_case(&Z)); 831 assert!(Z.eq_ignore_ascii_case(&z)); 832 assert!(!Z.eq_ignore_ascii_case(&DEL)); 833 } 834 835 #[test] 836 #[cfg(feature = "std")] ascii_ext()837 fn ascii_ext() { 838 #[allow(deprecated)] 839 use std::ascii::AsciiExt; 840 assert!(AsciiExt::is_ascii(&Null)); 841 assert!(AsciiExt::is_ascii(&DEL)); 842 assert!(AsciiExt::eq_ignore_ascii_case(&a, &A)); 843 assert!(!AsciiExt::eq_ignore_ascii_case(&A, &At)); 844 assert_eq!(AsciiExt::to_ascii_lowercase(&A), a); 845 assert_eq!(AsciiExt::to_ascii_uppercase(&A), A); 846 assert_eq!(AsciiExt::to_ascii_lowercase(&a), a); 847 assert_eq!(AsciiExt::to_ascii_uppercase(&a), A); 848 assert_eq!(AsciiExt::to_ascii_lowercase(&At), At); 849 assert_eq!(AsciiExt::to_ascii_uppercase(&At), At); 850 let mut mutable = (A,a); 851 AsciiExt::make_ascii_lowercase(&mut mutable.0); 852 AsciiExt::make_ascii_uppercase(&mut mutable.1); 853 assert_eq!(mutable.0, a); 854 assert_eq!(mutable.1, A); 855 } 856 857 #[test] 858 #[cfg(feature = "std")] fmt_ascii()859 fn fmt_ascii() { 860 assert_eq!(format!("{}", t), "t"); 861 assert_eq!(format!("{:?}", t), "'t'"); 862 assert_eq!(format!("{}", LineFeed), "\n"); 863 assert_eq!(format!("{:?}", LineFeed), "'\\n'"); 864 } 865 866 } 867