Skip to content

Commit

Permalink
Auto merge of #48978 - SimonSapin:debug-hex, r=KodrAus
Browse files Browse the repository at this point in the history
Add hexadecimal formatting of integers with fmt::Debug

This can be used for integers within a larger types which implements Debug (possibly through derive) but not fmt::UpperHex or fmt::LowerHex.

```rust
assert!(format!("{:02x?}", b"Foo\0") == "[46, 6f, 6f, 00]");
assert!(format!("{:02X?}", b"Foo\0") == "[46, 6F, 6F, 00]");
```

RFC: rust-lang/rfcs#2226

The new formatting string syntax (`x?` and `X?`) is insta-stable in this PR because I don’t know how to change a built-in proc macro’s behavior based of a feature gate. I can look into adding that, but I also strongly suspect that keeping this feature unstable for a time period would not be useful as possibly no-one would use it during that time.

This PR does not add the new (public) `fmt::Formatter` proposed in the API because:

* There was some skepticism on response to this part of the RFC
* It is not possible to implement as-is without larger changes to `fmt`, because `Formatter` at the moment has no easy way to tell apart for example `Octal` from `Binary`: it only has a function pointer for the relevant `fmt()` method.

If some integer-like type outside of `std` want to implement this behavior, another RFC will likely need to propose a different public API for `Formatter`.
  • Loading branch information
bors committed Mar 19, 2018
2 parents c2f4744 + 4897935 commit 152217d
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 4 deletions.
2 changes: 2 additions & 0 deletions src/liballoc/fmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@
//!
//! * *nothing* ⇒ [`Display`]
//! * `?` ⇒ [`Debug`]
//! * `x?` ⇒ [`Debug`] with lower-case hexadecimal integers
//! * `X?` ⇒ [`Debug`] with lower-case hexadecimal integers

This comment has been minimized.

Copy link
@ishitatsuyuki

ishitatsuyuki Mar 19, 2018

Contributor

@SimonSapin typo.

This comment has been minimized.

Copy link
@SimonSapin

SimonSapin Mar 19, 2018

Contributor

Oops. Filed #49161, thanks.

//! * `o` ⇒ [`Octal`](trait.Octal.html)
//! * `x` ⇒ [`LowerHex`](trait.LowerHex.html)
//! * `X` ⇒ [`UpperHex`](trait.UpperHex.html)
Expand Down
8 changes: 7 additions & 1 deletion src/libcore/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ impl<'a> ArgumentV1<'a> {

// flags available in the v1 format of format_args
#[derive(Copy, Clone)]
enum FlagV1 { SignPlus, SignMinus, Alternate, SignAwareZeroPad, }
enum FlagV1 { SignPlus, SignMinus, Alternate, SignAwareZeroPad, DebugLowerHex, DebugUpperHex }

impl<'a> Arguments<'a> {
/// When using the format_args!() macro, this function is used to generate the
Expand Down Expand Up @@ -1537,6 +1537,12 @@ impl<'a> Formatter<'a> {
self.flags & (1 << FlagV1::SignAwareZeroPad as u32) != 0
}

// FIXME: Decide what public API we want for these two flags.
// https://github.com/rust-lang/rust/issues/48584
fn debug_lower_hex(&self) -> bool { self.flags & (1 << FlagV1::DebugLowerHex as u32) != 0 }

fn debug_upper_hex(&self) -> bool { self.flags & (1 << FlagV1::DebugUpperHex as u32) != 0 }

/// Creates a [`DebugStruct`] builder designed to assist with creation of
/// [`fmt::Debug`] implementations for structs.
///
Expand Down
8 changes: 7 additions & 1 deletion src/libcore/fmt/num.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,13 @@ macro_rules! debug {
impl fmt::Debug for $T {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self, f)
if f.debug_lower_hex() {
fmt::LowerHex::fmt(self, f)
} else if f.debug_upper_hex() {
fmt::UpperHex::fmt(self, f)
} else {
fmt::Display::fmt(self, f)
}
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions src/libcore/tests/fmt/num.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,9 @@ fn test_format_int_twos_complement() {
assert!(format!("{}", i32::MIN) == "-2147483648");
assert!(format!("{}", i64::MIN) == "-9223372036854775808");
}

#[test]
fn test_format_debug_hex() {
assert!(format!("{:02x?}", b"Foo\0") == "[46, 6f, 6f, 00]");
assert!(format!("{:02X?}", b"Foo\0") == "[46, 6F, 6F, 00]");
}
22 changes: 20 additions & 2 deletions src/libfmt_macros/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ pub enum Flag {
/// For numbers, this means that the number will be padded with zeroes,
/// and the sign (`+` or `-`) will precede them.
FlagSignAwareZeroPad,
/// For Debug / `?`, format integers in lower-case hexadecimal.
FlagDebugLowerHex,
/// For Debug / `?`, format integers in upper-case hexadecimal.
FlagDebugUpperHex,
}

/// A count is used for the precision and width parameters of an integer, and
Expand Down Expand Up @@ -377,8 +381,22 @@ impl<'a> Parser<'a> {
spec.precision = self.count();
}
}
// Finally the actual format specifier
if self.consume('?') {
// Optional radix followed by the actual format specifier
if self.consume('x') {
if self.consume('?') {
spec.flags |= 1 << (FlagDebugLowerHex as u32);
spec.ty = "?";
} else {
spec.ty = "x";
}
} else if self.consume('X') {
if self.consume('?') {
spec.flags |= 1 << (FlagDebugUpperHex as u32);
spec.ty = "?";
} else {
spec.ty = "X";
}
} else if self.consume('?') {
spec.ty = "?";
} else {
spec.ty = self.word();
Expand Down

0 comments on commit 152217d

Please sign in to comment.