about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCorey Farwell <coreyf@rwell.org>2017-06-20 16:28:25 -0400
committerGitHub <noreply@github.com>2017-06-20 16:28:25 -0400
commit4c43bc32b723f0727456e7d40fb5feeeb1c4d448 (patch)
treea5718919322009fbdddaca0ff3d955c2292e3470
parent29bce6e220f6fd2292d13d65fe503af7bf4852b7 (diff)
parentfd9d7aa2cf76c949633cb4156642654238c03921 (diff)
downloadrust-4c43bc32b723f0727456e7d40fb5feeeb1c4d448.tar.gz
rust-4c43bc32b723f0727456e7d40fb5feeeb1c4d448.zip
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?
-rw-r--r--src/doc/unstable-book/src/library-features/char-error-internals.md5
-rw-r--r--src/libcore/char.rs59
-rw-r--r--src/libcore/tests/char.rs11
-rw-r--r--src/libstd/error.rs8
-rw-r--r--src/libstd/lib.rs1
-rw-r--r--src/libstd_unicode/char.rs2
6 files changed, 85 insertions, 1 deletions
diff --git a/src/doc/unstable-book/src/library-features/char-error-internals.md b/src/doc/unstable-book/src/library-features/char-error-internals.md
new file mode 100644
index 00000000000..8013b4988e1
--- /dev/null
+++ b/src/doc/unstable-book/src/library-features/char-error-internals.md
@@ -0,0 +1,5 @@
+# `char_error_internals`
+
+This feature is internal to the Rust compiler and is not intended for general use.
+
+------------------------
diff --git a/src/libcore/char.rs b/src/libcore/char.rs
index 98268e3813f..44f5fdbf431 100644
--- a/src/libcore/char.rs
+++ b/src/libcore/char.rs
@@ -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;
diff --git a/src/libcore/tests/char.rs b/src/libcore/tests/char.rs
index e4012ec91e2..7c3b90c8153 100644
--- a/src/libcore/tests/char.rs
+++ b/src/libcore/tests/char.rs
@@ -10,6 +10,7 @@
 
 use std::{char,str};
 use std::convert::TryFrom;
+use std::str::FromStr;
 
 #[test]
 fn test_convert() {
@@ -29,6 +30,16 @@ fn test_convert() {
 }
 
 #[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());
     assert!('รถ'.is_lowercase());
diff --git a/src/libstd/error.rs b/src/libstd/error.rs
index 3d203429e7b..4b340f70fbc 100644
--- a/src/libstd/error.rs
+++ b/src/libstd/error.rs
@@ -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`
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 7c843711dbe..bafe23e80a0 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -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)]
diff --git a/src/libstd_unicode/char.rs b/src/libstd_unicode/char.rs
index eb36cbe3b1f..d4d8993efb3 100644
--- a/src/libstd_unicode/char.rs
+++ b/src/libstd_unicode/char.rs
@@ -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")]