Auto merge of #83079 - osa1:issue83046, r=m-ou-se
Update char::escape_debug_ext to handle different escapes in strings and chars Fixes #83046 The program fn main() { println!("{:?}", '"'); println!("{:?}", "'"); } would previously print '\"' "\'" With this patch it now prints: '"' "'"
This commit is contained in:
commit
4137088d9d
7 changed files with 54 additions and 19 deletions
|
@ -68,10 +68,7 @@ fn test_format_macro_interface() {
|
|||
t!(format!("{:?}", 10_usize), "10");
|
||||
t!(format!("{:?}", "true"), "\"true\"");
|
||||
t!(format!("{:?}", "foo\nbar"), "\"foo\\nbar\"");
|
||||
t!(
|
||||
format!("{:?}", "foo\n\"bar\"\r\n\'baz\'\t\\qux\\"),
|
||||
r#""foo\n\"bar\"\r\n\'baz\'\t\\qux\\""#
|
||||
);
|
||||
t!(format!("{:?}", "foo\n\"bar\"\r\n\'baz\'\t\\qux\\"), r#""foo\n\"bar\"\r\n'baz'\t\\qux\\""#);
|
||||
t!(format!("{:?}", "foo\0bar\x01baz\u{7f}q\u{75}x"), r#""foo\u{0}bar\u{1}baz\u{7f}qux""#);
|
||||
t!(format!("{:o}", 10_usize), "12");
|
||||
t!(format!("{:x}", 10_usize), "a");
|
||||
|
|
|
@ -403,16 +403,20 @@ impl char {
|
|||
}
|
||||
|
||||
/// An extended version of `escape_debug` that optionally permits escaping
|
||||
/// Extended Grapheme codepoints. This allows us to format characters like
|
||||
/// nonspacing marks better when they're at the start of a string.
|
||||
/// Extended Grapheme codepoints, single quotes, and double quotes. This
|
||||
/// allows us to format characters like nonspacing marks better when they're
|
||||
/// at the start of a string, and allows escaping single quotes in
|
||||
/// characters, and double quotes in strings.
|
||||
#[inline]
|
||||
pub(crate) fn escape_debug_ext(self, escape_grapheme_extended: bool) -> EscapeDebug {
|
||||
pub(crate) fn escape_debug_ext(self, args: EscapeDebugExtArgs) -> EscapeDebug {
|
||||
let init_state = match self {
|
||||
'\t' => EscapeDefaultState::Backslash('t'),
|
||||
'\r' => EscapeDefaultState::Backslash('r'),
|
||||
'\n' => EscapeDefaultState::Backslash('n'),
|
||||
'\\' | '\'' | '"' => EscapeDefaultState::Backslash(self),
|
||||
_ if escape_grapheme_extended && self.is_grapheme_extended() => {
|
||||
'\\' => EscapeDefaultState::Backslash(self),
|
||||
'"' if args.escape_double_quote => EscapeDefaultState::Backslash(self),
|
||||
'\'' if args.escape_single_quote => EscapeDefaultState::Backslash(self),
|
||||
_ if args.escape_grapheme_extended && self.is_grapheme_extended() => {
|
||||
EscapeDefaultState::Unicode(self.escape_unicode())
|
||||
}
|
||||
_ if is_printable(self) => EscapeDefaultState::Char(self),
|
||||
|
@ -458,7 +462,7 @@ impl char {
|
|||
#[stable(feature = "char_escape_debug", since = "1.20.0")]
|
||||
#[inline]
|
||||
pub fn escape_debug(self) -> EscapeDebug {
|
||||
self.escape_debug_ext(true)
|
||||
self.escape_debug_ext(EscapeDebugExtArgs::ESCAPE_ALL)
|
||||
}
|
||||
|
||||
/// Returns an iterator that yields the literal escape code of a character
|
||||
|
@ -1565,6 +1569,25 @@ impl char {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) struct EscapeDebugExtArgs {
|
||||
/// Escape Extended Grapheme codepoints?
|
||||
pub(crate) escape_grapheme_extended: bool,
|
||||
|
||||
/// Escape single quotes?
|
||||
pub(crate) escape_single_quote: bool,
|
||||
|
||||
/// Escape double quotes?
|
||||
pub(crate) escape_double_quote: bool,
|
||||
}
|
||||
|
||||
impl EscapeDebugExtArgs {
|
||||
pub(crate) const ESCAPE_ALL: Self = Self {
|
||||
escape_grapheme_extended: true,
|
||||
escape_single_quote: true,
|
||||
escape_double_quote: true,
|
||||
};
|
||||
}
|
||||
|
||||
#[inline]
|
||||
const fn len_utf8(code: u32) -> usize {
|
||||
if code < MAX_ONE_B {
|
||||
|
|
|
@ -45,6 +45,8 @@ pub use self::methods::encode_utf8_raw;
|
|||
use crate::fmt::{self, Write};
|
||||
use crate::iter::FusedIterator;
|
||||
|
||||
pub(crate) use self::methods::EscapeDebugExtArgs;
|
||||
|
||||
// UTF-8 ranges and tags for encoding characters
|
||||
const TAG_CONT: u8 = 0b1000_0000;
|
||||
const TAG_TWO_B: u8 = 0b1100_0000;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
use crate::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell};
|
||||
use crate::char::EscapeDebugExtArgs;
|
||||
use crate::marker::PhantomData;
|
||||
use crate::mem;
|
||||
use crate::num::flt2dec;
|
||||
|
@ -2054,7 +2055,11 @@ impl Debug for str {
|
|||
f.write_char('"')?;
|
||||
let mut from = 0;
|
||||
for (i, c) in self.char_indices() {
|
||||
let esc = c.escape_debug();
|
||||
let esc = c.escape_debug_ext(EscapeDebugExtArgs {
|
||||
escape_grapheme_extended: true,
|
||||
escape_single_quote: false,
|
||||
escape_double_quote: true,
|
||||
});
|
||||
// If char needs escaping, flush backlog so far and write, else skip
|
||||
if esc.len() != 1 {
|
||||
f.write_str(&self[from..i])?;
|
||||
|
@ -2080,7 +2085,11 @@ impl Display for str {
|
|||
impl Debug for char {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||
f.write_char('\'')?;
|
||||
for c in self.escape_debug() {
|
||||
for c in self.escape_debug_ext(EscapeDebugExtArgs {
|
||||
escape_grapheme_extended: true,
|
||||
escape_single_quote: true,
|
||||
escape_double_quote: false,
|
||||
}) {
|
||||
f.write_char(c)?
|
||||
}
|
||||
f.write_char('\'')
|
||||
|
|
|
@ -15,7 +15,7 @@ mod validations;
|
|||
use self::pattern::Pattern;
|
||||
use self::pattern::{DoubleEndedSearcher, ReverseSearcher, Searcher};
|
||||
|
||||
use crate::char;
|
||||
use crate::char::{self, EscapeDebugExtArgs};
|
||||
use crate::mem;
|
||||
use crate::slice::{self, SliceIndex};
|
||||
|
||||
|
@ -2342,7 +2342,7 @@ impl str {
|
|||
EscapeDebug {
|
||||
inner: chars
|
||||
.next()
|
||||
.map(|first| first.escape_debug_ext(true))
|
||||
.map(|first| first.escape_debug_ext(EscapeDebugExtArgs::ESCAPE_ALL))
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.chain(chars.flat_map(CharEscapeDebugContinue)),
|
||||
|
@ -2460,7 +2460,11 @@ impl_fn_for_zst! {
|
|||
|
||||
#[derive(Clone)]
|
||||
struct CharEscapeDebugContinue impl Fn = |c: char| -> char::EscapeDebug {
|
||||
c.escape_debug_ext(false)
|
||||
c.escape_debug_ext(EscapeDebugExtArgs {
|
||||
escape_grapheme_extended: false,
|
||||
escape_single_quote: true,
|
||||
escape_double_quote: true
|
||||
})
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
|
@ -10,7 +10,7 @@ error: doc alias attribute expects a string `#[doc(alias = "a")]` or a list of s
|
|||
LL | #[doc(alias = 0)]
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: '\"' character isn't allowed in `#[doc(alias = "...")]`
|
||||
error: '"' character isn't allowed in `#[doc(alias = "...")]`
|
||||
--> $DIR/check-doc-alias-attr.rs:9:15
|
||||
|
|
||||
LL | #[doc(alias = "\"")]
|
||||
|
@ -60,7 +60,7 @@ error: `#[doc(alias("a"))]` expects string literals
|
|||
LL | #[doc(alias(0))]
|
||||
| ^
|
||||
|
||||
error: '\"' character isn't allowed in `#[doc(alias("..."))]`
|
||||
error: '"' character isn't allowed in `#[doc(alias("..."))]`
|
||||
--> $DIR/check-doc-alias-attr.rs:20:13
|
||||
|
|
||||
LL | #[doc(alias("\""))]
|
||||
|
|
|
@ -10,7 +10,7 @@ error: doc alias attribute expects a string `#[doc(alias = "a")]` or a list of s
|
|||
LL | #[doc(alias = 0)]
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: '\"' character isn't allowed in `#[doc(alias = "...")]`
|
||||
error: '"' character isn't allowed in `#[doc(alias = "...")]`
|
||||
--> $DIR/check-doc-alias-attr.rs:9:15
|
||||
|
|
||||
LL | #[doc(alias = "\"")]
|
||||
|
@ -60,7 +60,7 @@ error: `#[doc(alias("a"))]` expects string literals
|
|||
LL | #[doc(alias(0))]
|
||||
| ^
|
||||
|
||||
error: '\"' character isn't allowed in `#[doc(alias("..."))]`
|
||||
error: '"' character isn't allowed in `#[doc(alias("..."))]`
|
||||
--> $DIR/check-doc-alias-attr.rs:20:13
|
||||
|
|
||||
LL | #[doc(alias("\""))]
|
||||
|
|
Loading…
Add table
Reference in a new issue