From 3a79f2e2f1b1e07066f9e4a8fdc38816e5a0b6e7 Mon Sep 17 00:00:00 2001 From: Clar Charr Date: Sat, 7 Jan 2017 13:16:03 -0500 Subject: [PATCH] Implement Display for char Escape*, To*case. --- src/libcore/char.rs | 29 ++++- src/libcoretest/char.rs | 224 ++++++++++++++++--------------------- src/libstd_unicode/char.rs | 199 ++++++++++++++++++++++++-------- 3 files changed, 277 insertions(+), 175 deletions(-) diff --git a/src/libcore/char.rs b/src/libcore/char.rs index c14ae6e089873..367422f55364a 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -17,7 +17,7 @@ use char_private::is_printable; use convert::TryFrom; -use fmt; +use fmt::{self, Write}; use slice; use iter::FusedIterator; use mem::transmute; @@ -588,6 +588,16 @@ impl ExactSizeIterator for EscapeUnicode { #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for EscapeUnicode {} +#[stable(feature = "char_struct_display", since = "1.17.0")] +impl fmt::Display for EscapeUnicode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + for c in self.clone() { + f.write_char(c)?; + } + Ok(()) + } +} + /// An iterator that yields the literal escape code of a `char`. /// /// This `struct` is created by the [`escape_default()`] method on [`char`]. See @@ -691,6 +701,16 @@ impl ExactSizeIterator for EscapeDefault { #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for EscapeDefault {} +#[stable(feature = "char_struct_display", since = "1.17.0")] +impl fmt::Display for EscapeDefault { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + for c in self.clone() { + f.write_char(c)?; + } + Ok(()) + } +} + /// An iterator that yields the literal escape code of a `char`. /// /// This `struct` is created by the [`escape_debug()`] method on [`char`]. See its @@ -715,6 +735,13 @@ impl ExactSizeIterator for EscapeDebug { } #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for EscapeDebug {} +#[stable(feature = "char_struct_display", since = "1.17.0")] +impl fmt::Display for EscapeDebug { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} + /// An iterator over an iterator of bytes of the characters the bytes represent diff --git a/src/libcoretest/char.rs b/src/libcoretest/char.rs index b4088ffbf89a9..e4012ec91e2b3 100644 --- a/src/libcoretest/char.rs +++ b/src/libcoretest/char.rs @@ -75,47 +75,53 @@ fn test_to_digit() { #[test] fn test_to_lowercase() { - fn lower(c: char) -> Vec { - c.to_lowercase().collect() + fn lower(c: char) -> String { + let iter: String = c.to_lowercase().collect(); + let disp: String = c.to_lowercase().to_string(); + assert_eq!(iter, disp); + iter } - assert_eq!(lower('A'), ['a']); - assert_eq!(lower('Ö'), ['ö']); - assert_eq!(lower('ß'), ['ß']); - assert_eq!(lower('Ü'), ['ü']); - assert_eq!(lower('💩'), ['💩']); - assert_eq!(lower('Σ'), ['σ']); - assert_eq!(lower('Τ'), ['τ']); - assert_eq!(lower('Ι'), ['ι']); - assert_eq!(lower('Γ'), ['γ']); - assert_eq!(lower('Μ'), ['μ']); - assert_eq!(lower('Α'), ['α']); - assert_eq!(lower('Σ'), ['σ']); - assert_eq!(lower('Dž'), ['dž']); - assert_eq!(lower('fi'), ['fi']); - assert_eq!(lower('İ'), ['i', '\u{307}']); + assert_eq!(lower('A'), "a"); + assert_eq!(lower('Ö'), "ö"); + assert_eq!(lower('ß'), "ß"); + assert_eq!(lower('Ü'), "ü"); + assert_eq!(lower('💩'), "💩"); + assert_eq!(lower('Σ'), "σ"); + assert_eq!(lower('Τ'), "τ"); + assert_eq!(lower('Ι'), "ι"); + assert_eq!(lower('Γ'), "γ"); + assert_eq!(lower('Μ'), "μ"); + assert_eq!(lower('Α'), "α"); + assert_eq!(lower('Σ'), "σ"); + assert_eq!(lower('Dž'), "dž"); + assert_eq!(lower('fi'), "fi"); + assert_eq!(lower('İ'), "i\u{307}"); } #[test] fn test_to_uppercase() { - fn upper(c: char) -> Vec { - c.to_uppercase().collect() + fn upper(c: char) -> String { + let iter: String = c.to_uppercase().collect(); + let disp: String = c.to_uppercase().to_string(); + assert_eq!(iter, disp); + iter } - assert_eq!(upper('a'), ['A']); - assert_eq!(upper('ö'), ['Ö']); - assert_eq!(upper('ß'), ['S', 'S']); // not ẞ: Latin capital letter sharp s - assert_eq!(upper('ü'), ['Ü']); - assert_eq!(upper('💩'), ['💩']); - - assert_eq!(upper('σ'), ['Σ']); - assert_eq!(upper('τ'), ['Τ']); - assert_eq!(upper('ι'), ['Ι']); - assert_eq!(upper('γ'), ['Γ']); - assert_eq!(upper('μ'), ['Μ']); - assert_eq!(upper('α'), ['Α']); - assert_eq!(upper('ς'), ['Σ']); - assert_eq!(upper('Dž'), ['DŽ']); - assert_eq!(upper('fi'), ['F', 'I']); - assert_eq!(upper('ᾀ'), ['Ἀ', 'Ι']); + assert_eq!(upper('a'), "A"); + assert_eq!(upper('ö'), "Ö"); + assert_eq!(upper('ß'), "SS"); // not ẞ: Latin capital letter sharp s + assert_eq!(upper('ü'), "Ü"); + assert_eq!(upper('💩'), "💩"); + + assert_eq!(upper('σ'), "Σ"); + assert_eq!(upper('τ'), "Τ"); + assert_eq!(upper('ι'), "Ι"); + assert_eq!(upper('γ'), "Γ"); + assert_eq!(upper('μ'), "Μ"); + assert_eq!(upper('α'), "Α"); + assert_eq!(upper('ς'), "Σ"); + assert_eq!(upper('Dž'), "DŽ"); + assert_eq!(upper('fi'), "FI"); + assert_eq!(upper('ᾀ'), "ἈΙ"); } #[test] @@ -144,107 +150,75 @@ fn test_is_digit() { #[test] fn test_escape_debug() { fn string(c: char) -> String { - c.escape_debug().collect() + let iter: String = c.escape_debug().collect(); + let disp: String = c.escape_debug().to_string(); + assert_eq!(iter, disp); + iter } - let s = string('\n'); - assert_eq!(s, "\\n"); - let s = string('\r'); - assert_eq!(s, "\\r"); - let s = string('\''); - assert_eq!(s, "\\'"); - let s = string('"'); - assert_eq!(s, "\\\""); - let s = string(' '); - assert_eq!(s, " "); - let s = string('a'); - assert_eq!(s, "a"); - let s = string('~'); - assert_eq!(s, "~"); - let s = string('é'); - assert_eq!(s, "é"); - let s = string('文'); - assert_eq!(s, "文"); - let s = string('\x00'); - assert_eq!(s, "\\u{0}"); - let s = string('\x1f'); - assert_eq!(s, "\\u{1f}"); - let s = string('\x7f'); - assert_eq!(s, "\\u{7f}"); - let s = string('\u{80}'); - assert_eq!(s, "\\u{80}"); - let s = string('\u{ff}'); - assert_eq!(s, "\u{ff}"); - let s = string('\u{11b}'); - assert_eq!(s, "\u{11b}"); - let s = string('\u{1d4b6}'); - assert_eq!(s, "\u{1d4b6}"); - let s = string('\u{200b}'); // zero width space - assert_eq!(s, "\\u{200b}"); - let s = string('\u{e000}'); // private use 1 - assert_eq!(s, "\\u{e000}"); - let s = string('\u{100000}'); // private use 2 - assert_eq!(s, "\\u{100000}"); + assert_eq!(string('\n'), "\\n"); + assert_eq!(string('\r'), "\\r"); + assert_eq!(string('\''), "\\'"); + assert_eq!(string('"'), "\\\""); + assert_eq!(string(' '), " "); + assert_eq!(string('a'), "a"); + assert_eq!(string('~'), "~"); + assert_eq!(string('é'), "é"); + assert_eq!(string('文'), "文"); + assert_eq!(string('\x00'), "\\u{0}"); + assert_eq!(string('\x1f'), "\\u{1f}"); + assert_eq!(string('\x7f'), "\\u{7f}"); + assert_eq!(string('\u{80}'), "\\u{80}"); + assert_eq!(string('\u{ff}'), "\u{ff}"); + assert_eq!(string('\u{11b}'), "\u{11b}"); + assert_eq!(string('\u{1d4b6}'), "\u{1d4b6}"); + assert_eq!(string('\u{200b}'),"\\u{200b}"); // zero width space + assert_eq!(string('\u{e000}'), "\\u{e000}"); // private use 1 + assert_eq!(string('\u{100000}'), "\\u{100000}"); // private use 2 } #[test] fn test_escape_default() { fn string(c: char) -> String { - c.escape_default().collect() + let iter: String = c.escape_default().collect(); + let disp: String = c.escape_default().to_string(); + assert_eq!(iter, disp); + iter } - let s = string('\n'); - assert_eq!(s, "\\n"); - let s = string('\r'); - assert_eq!(s, "\\r"); - let s = string('\''); - assert_eq!(s, "\\'"); - let s = string('"'); - assert_eq!(s, "\\\""); - let s = string(' '); - assert_eq!(s, " "); - let s = string('a'); - assert_eq!(s, "a"); - let s = string('~'); - assert_eq!(s, "~"); - let s = string('é'); - assert_eq!(s, "\\u{e9}"); - let s = string('\x00'); - assert_eq!(s, "\\u{0}"); - let s = string('\x1f'); - assert_eq!(s, "\\u{1f}"); - let s = string('\x7f'); - assert_eq!(s, "\\u{7f}"); - let s = string('\u{80}'); - assert_eq!(s, "\\u{80}"); - let s = string('\u{ff}'); - assert_eq!(s, "\\u{ff}"); - let s = string('\u{11b}'); - assert_eq!(s, "\\u{11b}"); - let s = string('\u{1d4b6}'); - assert_eq!(s, "\\u{1d4b6}"); - let s = string('\u{200b}'); // zero width space - assert_eq!(s, "\\u{200b}"); - let s = string('\u{e000}'); // private use 1 - assert_eq!(s, "\\u{e000}"); - let s = string('\u{100000}'); // private use 2 - assert_eq!(s, "\\u{100000}"); + assert_eq!(string('\n'), "\\n"); + assert_eq!(string('\r'), "\\r"); + assert_eq!(string('\''), "\\'"); + assert_eq!(string('"'), "\\\""); + assert_eq!(string(' '), " "); + assert_eq!(string('a'), "a"); + assert_eq!(string('~'), "~"); + assert_eq!(string('é'), "\\u{e9}"); + assert_eq!(string('\x00'), "\\u{0}"); + assert_eq!(string('\x1f'), "\\u{1f}"); + assert_eq!(string('\x7f'), "\\u{7f}"); + assert_eq!(string('\u{80}'), "\\u{80}"); + assert_eq!(string('\u{ff}'), "\\u{ff}"); + assert_eq!(string('\u{11b}'), "\\u{11b}"); + assert_eq!(string('\u{1d4b6}'), "\\u{1d4b6}"); + assert_eq!(string('\u{200b}'), "\\u{200b}"); // zero width space + assert_eq!(string('\u{e000}'), "\\u{e000}"); // private use 1 + assert_eq!(string('\u{100000}'), "\\u{100000}"); // private use 2 } #[test] fn test_escape_unicode() { - fn string(c: char) -> String { c.escape_unicode().collect() } - - let s = string('\x00'); - assert_eq!(s, "\\u{0}"); - let s = string('\n'); - assert_eq!(s, "\\u{a}"); - let s = string(' '); - assert_eq!(s, "\\u{20}"); - let s = string('a'); - assert_eq!(s, "\\u{61}"); - let s = string('\u{11b}'); - assert_eq!(s, "\\u{11b}"); - let s = string('\u{1d4b6}'); - assert_eq!(s, "\\u{1d4b6}"); + fn string(c: char) -> String { + let iter: String = c.escape_unicode().collect(); + let disp: String = c.escape_unicode().to_string(); + assert_eq!(iter, disp); + iter + } + + assert_eq!(string('\x00'), "\\u{0}"); + assert_eq!(string('\n'), "\\u{a}"); + assert_eq!(string(' '), "\\u{20}"); + assert_eq!(string('a'), "\\u{61}"); + assert_eq!(string('\u{11b}'), "\\u{11b}"); + assert_eq!(string('\u{1d4b6}'), "\\u{1d4b6}"); } #[test] diff --git a/src/libstd_unicode/char.rs b/src/libstd_unicode/char.rs index 53dafadb5d568..f2c53efda1737 100644 --- a/src/libstd_unicode/char.rs +++ b/src/libstd_unicode/char.rs @@ -30,7 +30,7 @@ use core::char::CharExt as C; use core::iter::FusedIterator; -use core::fmt; +use core::fmt::{self, Write}; use tables::{conversions, derived_property, general_category, property}; // stable reexports @@ -131,6 +131,41 @@ impl Iterator for CaseMappingIter { } } +#[stable(feature = "char_struct_display", since = "1.17.0")] +impl fmt::Display for CaseMappingIter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + CaseMappingIter::Three(a, b, c) => { + f.write_char(a)?; + f.write_char(b)?; + f.write_char(c) + } + CaseMappingIter::Two(b, c) => { + f.write_char(b)?; + f.write_char(c) + } + CaseMappingIter::One(c) => { + f.write_char(c) + } + CaseMappingIter::Zero => Ok(()), + } + } +} + +#[stable(feature = "char_struct_display", since = "1.17.0")] +impl fmt::Display for ToLowercase { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} + +#[stable(feature = "char_struct_display", since = "1.17.0")] +impl fmt::Display for ToUppercase { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} + #[lang = "char"] impl char { /// Checks if a `char` is a digit in the given radix. @@ -240,34 +275,38 @@ impl char { } /// Returns an iterator that yields the hexadecimal Unicode escape of a - /// character, as `char`s. + /// character as `char`s. /// - /// All characters are escaped with Rust syntax of the form `\u{NNNNNN}` - /// where `NNNNNN` is the shortest hexadecimal representation. + /// This will escape characters with the Rust syntax of the form + /// `\u{NNNNNN}` where `NNNNNN` is a hexadecimal representation. /// /// # Examples /// - /// Basic usage: + /// As an iterator: /// /// ``` /// for c in '❤'.escape_unicode() { /// print!("{}", c); /// } - /// println!(""); + /// println!(); /// ``` /// - /// This prints: + /// Using `println!` directly: /// - /// ```text - /// \u{2764} + /// ``` + /// println!("{}", '❤'.escape_unicode()); /// ``` /// - /// Collecting into a `String`: + /// Both are equivalent to: /// /// ``` - /// let heart: String = '❤'.escape_unicode().collect(); + /// println!("\\u{{2764}}"); + /// ``` /// - /// assert_eq!(heart, r"\u{2764}"); + /// Using `to_string`: + /// + /// ``` + /// assert_eq!('❤'.escape_unicode().to_string(), "\\u{2764}"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -275,34 +314,42 @@ impl char { C::escape_unicode(self) } - /// Returns an iterator that yields the literal escape code of a `char`. + /// Returns an iterator that yields the literal escape code of a character + /// as `char`s. /// /// This will escape the characters similar to the `Debug` implementations /// of `str` or `char`. /// /// # Examples /// - /// Basic usage: + /// As an iterator: /// /// ``` - /// for i in '\n'.escape_default() { - /// println!("{}", i); + /// # #![feature(char_escape_debug)] + /// for c in '\n'.escape_debug() { + /// print!("{}", c); /// } + /// println!(); /// ``` /// - /// This prints: + /// Using `println!` directly: /// - /// ```text - /// \ - /// n + /// ``` + /// # #![feature(char_escape_debug)] + /// println!("{}", '\n'.escape_debug()); /// ``` /// - /// Collecting into a `String`: + /// Both are equivalent to: /// /// ``` - /// let quote: String = '\n'.escape_default().collect(); + /// println!("\\n"); + /// ``` /// - /// assert_eq!(quote, "\\n"); + /// Using `to_string`: + /// + /// ``` + /// # #![feature(char_escape_debug)] + /// assert_eq!('\n'.escape_debug().to_string(), "\\n"); /// ``` #[unstable(feature = "char_escape_debug", issue = "35068")] #[inline] @@ -310,7 +357,8 @@ impl char { C::escape_debug(self) } - /// Returns an iterator that yields the literal escape code of a `char`. + /// Returns an iterator that yields the literal escape code of a character + /// as `char`s. /// /// The default is chosen with a bias toward producing literals that are /// legal in a variety of languages, including C++11 and similar C-family @@ -331,27 +379,32 @@ impl char { /// /// # Examples /// - /// Basic usage: + /// As an iterator: /// /// ``` - /// for i in '"'.escape_default() { - /// println!("{}", i); + /// for c in '"'.escape_default() { + /// print!("{}", c); /// } + /// println!(); /// ``` /// - /// This prints: + /// Using `println!` directly: /// - /// ```text - /// \ - /// " /// ``` + /// println!("{}", '"'.escape_default()); + /// ``` + /// /// - /// Collecting into a `String`: + /// Both are equivalent to: /// /// ``` - /// let quote: String = '"'.escape_default().collect(); + /// println!("\\\""); + /// ``` + /// + /// Using `to_string`: /// - /// assert_eq!(quote, "\\\""); + /// ``` + /// assert_eq!('"'.escape_default().to_string(), "\\\""); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -726,9 +779,11 @@ impl char { } } - /// Returns an iterator that yields the lowercase equivalent of a `char`. + /// Returns an iterator that yields the lowercase equivalent of a `char` + /// as one or more `char`s. /// - /// If no conversion is possible then an iterator with just the input character is returned. + /// If a character does not have a lowercase equivalent, the same character + /// will be returned back by the iterator. /// /// This performs complex unconditional mappings with no tailoring: it maps /// one Unicode character to its lowercase equivalent according to the @@ -746,16 +801,37 @@ impl char { /// /// # Examples /// - /// Basic usage: + /// As an iterator: + /// + /// ``` + /// for c in 'İ'.to_lowercase() { + /// print!("{}", c); + /// } + /// println!(); + /// ``` + /// + /// Using `println!` directly: + /// + /// ``` + /// println!("{}", 'İ'.to_lowercase()); + /// ``` + /// + /// Both are equivalent to: + /// + /// ``` + /// println!("i\u{307}"); + /// ``` + /// + /// Using `to_string`: /// /// ``` - /// assert_eq!('C'.to_lowercase().collect::(), "c"); + /// assert_eq!('C'.to_lowercase().to_string(), "c"); /// /// // Sometimes the result is more than one character: - /// assert_eq!('İ'.to_lowercase().collect::(), "i\u{307}"); + /// assert_eq!('İ'.to_lowercase().to_string(), "i\u{307}"); /// /// // Japanese scripts do not have case, and so: - /// assert_eq!('山'.to_lowercase().collect::(), "山"); + /// assert_eq!('山'.to_lowercase().to_string(), "山"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -763,12 +839,14 @@ impl char { ToLowercase(CaseMappingIter::new(conversions::to_lower(self))) } - /// Returns an iterator that yields the uppercase equivalent of a `char`. + /// Returns an iterator that yields the uppercase equivalent of a `char` + /// as one or more `char`s. /// - /// If no conversion is possible then an iterator with just the input character is returned. + /// If a character does not have a uppercase equivalent, the same character + /// will be returned back by the iterator. /// /// This performs complex unconditional mappings with no tailoring: it maps - /// one Unicode character to its uppercase equivalent according to the + /// one Unicode character to its lowercase equivalent according to the /// [Unicode database] and the additional complex mappings /// [`SpecialCasing.txt`]. Conditional mappings (based on context or /// language) are not considered here. @@ -783,18 +861,41 @@ impl char { /// /// # Examples /// - /// Basic usage: + /// As an iterator: /// /// ``` - /// assert_eq!('c'.to_uppercase().collect::(), "C"); + /// for c in 'ß'.to_uppercase() { + /// print!("{}", c); + /// } + /// println!(); + /// ``` + /// + /// Using `println!` directly: + /// + /// ``` + /// println!("{}", 'ß'.to_uppercase()); + /// ``` + /// + /// Both are equivalent to: + /// + /// ``` + /// println!("SS"); + /// ``` + /// + /// Using `to_string`: + /// + /// ``` + /// assert_eq!('c'.to_uppercase().to_string(), "C"); /// /// // Sometimes the result is more than one character: - /// assert_eq!('ß'.to_uppercase().collect::(), "SS"); + /// assert_eq!('ß'.to_uppercase().to_string(), "SS"); /// /// // Japanese does not have case, and so: - /// assert_eq!('山'.to_uppercase().collect::(), "山"); + /// assert_eq!('山'.to_uppercase().to_string(), "山"); /// ``` /// + /// # Note on locale + /// /// In Turkish, the equivalent of 'i' in Latin has five forms instead of two: /// /// * 'Dotless': I / ı, sometimes written ï @@ -803,7 +904,7 @@ impl char { /// Note that the lowercase dotted 'i' is the same as the Latin. Therefore: /// /// ``` - /// let upper_i: String = 'i'.to_uppercase().collect(); + /// let upper_i = 'i'.to_uppercase().to_string(); /// ``` /// /// The value of `upper_i` here relies on the language of the text: if we're @@ -811,7 +912,7 @@ impl char { /// be `"İ"`. `to_uppercase()` does not take this into account, and so: /// /// ``` - /// let upper_i: String = 'i'.to_uppercase().collect(); + /// let upper_i = 'i'.to_uppercase().to_string(); /// /// assert_eq!(upper_i, "I"); /// ```