Rollup merge of #42271 - tinaun:charfromstr, r=alexcrichton

add `FromStr` Impl for `char`

fixes #24939.

is it possible to use pub(restricted) instead of using a stability attribute for the internal error representation? is it needed at all?
This commit is contained in:
Corey Farwell 2017-06-20 16:28:25 -04:00 committed by GitHub
commit 4c43bc32b7
6 changed files with 85 additions and 1 deletions

View File

@ -0,0 +1,5 @@
# `char_error_internals`
This feature is internal to the Rust compiler and is not intended for general use.
------------------------

View File

@ -19,7 +19,7 @@ use char_private::is_printable;
use convert::TryFrom;
use fmt::{self, Write};
use slice;
use str::from_utf8_unchecked_mut;
use str::{from_utf8_unchecked_mut, FromStr};
use iter::FusedIterator;
use mem::transmute;
@ -208,6 +208,63 @@ impl From<u8> for char {
}
}
/// An error which can be returned when parsing a char.
#[stable(feature = "char_from_str", since = "1.19.0")]
#[derive(Clone, Debug)]
pub struct ParseCharError {
kind: CharErrorKind,
}
impl ParseCharError {
#[unstable(feature = "char_error_internals",
reason = "this method should not be available publicly",
issue = "0")]
#[doc(hidden)]
pub fn __description(&self) -> &str {
match self.kind {
CharErrorKind::EmptyString => {
"cannot parse char from empty string"
},
CharErrorKind::TooManyChars => "too many characters in string"
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum CharErrorKind {
EmptyString,
TooManyChars,
}
#[stable(feature = "char_from_str", since = "1.19.0")]
impl fmt::Display for ParseCharError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.__description().fmt(f)
}
}
#[stable(feature = "char_from_str", since = "1.19.0")]
impl FromStr for char {
type Err = ParseCharError;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut chars = s.chars();
match (chars.next(), chars.next()) {
(None, _) => {
Err(ParseCharError { kind: CharErrorKind::EmptyString })
},
(Some(c), None) => Ok(c),
_ => {
Err(ParseCharError { kind: CharErrorKind::TooManyChars })
}
}
}
}
#[unstable(feature = "try_from", issue = "33417")]
impl TryFrom<u32> for char {
type Error = CharTryFromError;

View File

@ -10,6 +10,7 @@
use std::{char,str};
use std::convert::TryFrom;
use std::str::FromStr;
#[test]
fn test_convert() {
@ -28,6 +29,16 @@ fn test_convert() {
assert!(char::try_from(0xFFFF_FFFF_u32).is_err());
}
#[test]
fn test_from_str() {
assert_eq!(char::from_str("a").unwrap(), 'a');
assert_eq!(char::try_from("a").unwrap(), 'a');
assert_eq!(char::from_str("\0").unwrap(), '\0');
assert_eq!(char::from_str("\u{D7FF}").unwrap(), '\u{d7FF}');
assert!(char::from_str("").is_err());
assert!(char::from_str("abc").is_err());
}
#[test]
fn test_is_lowercase() {
assert!('a'.is_lowercase());

View File

@ -340,6 +340,14 @@ impl Error for char::CharTryFromError {
}
}
#[stable(feature = "char_from_str", since = "1.19.0")]
impl Error for char::ParseCharError {
fn description(&self) -> &str {
self.__description()
}
}
// copied from any.rs
impl Error + 'static {
/// Returns true if the boxed type is the same as `T`

View File

@ -254,6 +254,7 @@
#![feature(cfg_target_thread_local)]
#![feature(cfg_target_vendor)]
#![feature(char_escape_debug)]
#![feature(char_error_internals)]
#![feature(char_internals)]
#![feature(collections_range)]
#![feature(compiler_builtins_lib)]

View File

@ -38,6 +38,8 @@ use tables::{conversions, derived_property, general_category, property};
pub use core::char::{MAX, from_digit, from_u32, from_u32_unchecked};
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::char::{EscapeDebug, EscapeDefault, EscapeUnicode};
#[stable(feature = "char_from_str", since = "1.19.0")]
pub use core::char::ParseCharError;
// unstable reexports
#[unstable(feature = "try_from", issue = "33417")]