summaryrefslogtreecommitdiffstats
path: root/library/core/src/fmt
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
commitef24de24a82fe681581cc130f342363c47c0969a (patch)
tree0d494f7e1a38b95c92426f58fe6eaa877303a86c /library/core/src/fmt
parentReleasing progress-linux version 1.74.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-ef24de24a82fe681581cc130f342363c47c0969a.tar.xz
rustc-ef24de24a82fe681581cc130f342363c47c0969a.zip
Merging upstream version 1.75.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'library/core/src/fmt')
-rw-r--r--library/core/src/fmt/builders.rs145
-rw-r--r--library/core/src/fmt/mod.rs10
-rw-r--r--library/core/src/fmt/rt.rs4
3 files changed, 144 insertions, 15 deletions
diff --git a/library/core/src/fmt/builders.rs b/library/core/src/fmt/builders.rs
index 922724804..4ccb58586 100644
--- a/library/core/src/fmt/builders.rs
+++ b/library/core/src/fmt/builders.rs
@@ -84,6 +84,7 @@ impl fmt::Write for PadAdapter<'_, '_> {
#[must_use = "must eventually call `finish()` on Debug builders"]
#[allow(missing_debug_implementations)]
#[stable(feature = "debug_builders", since = "1.2.0")]
+#[rustc_diagnostic_item = "DebugStruct"]
pub struct DebugStruct<'a, 'b: 'a> {
fmt: &'a mut fmt::Formatter<'b>,
result: fmt::Result,
@@ -129,6 +130,18 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
/// ```
#[stable(feature = "debug_builders", since = "1.2.0")]
pub fn field(&mut self, name: &str, value: &dyn fmt::Debug) -> &mut Self {
+ self.field_with(name, |f| value.fmt(f))
+ }
+
+ /// Adds a new field to the generated struct output.
+ ///
+ /// This method is equivalent to [`DebugStruct::field`], but formats the
+ /// value using a provided closure rather than by calling [`Debug::fmt`].
+ #[unstable(feature = "debug_closure_helpers", issue = "117729")]
+ pub fn field_with<F>(&mut self, name: &str, value_fmt: F) -> &mut Self
+ where
+ F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result,
+ {
self.result = self.result.and_then(|_| {
if self.is_pretty() {
if !self.has_fields {
@@ -139,14 +152,14 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
let mut writer = PadAdapter::wrap(self.fmt, &mut slot, &mut state);
writer.write_str(name)?;
writer.write_str(": ")?;
- value.fmt(&mut writer)?;
+ value_fmt(&mut writer)?;
writer.write_str(",\n")
} else {
let prefix = if self.has_fields { ", " } else { " { " };
self.fmt.write_str(prefix)?;
self.fmt.write_str(name)?;
self.fmt.write_str(": ")?;
- value.fmt(self.fmt)
+ value_fmt(self.fmt)
}
});
@@ -314,6 +327,18 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> {
/// ```
#[stable(feature = "debug_builders", since = "1.2.0")]
pub fn field(&mut self, value: &dyn fmt::Debug) -> &mut Self {
+ self.field_with(|f| value.fmt(f))
+ }
+
+ /// Adds a new field to the generated tuple struct output.
+ ///
+ /// This method is equivalent to [`DebugTuple::field`], but formats the
+ /// value using a provided closure rather than by calling [`Debug::fmt`].
+ #[unstable(feature = "debug_closure_helpers", issue = "117729")]
+ pub fn field_with<F>(&mut self, value_fmt: F) -> &mut Self
+ where
+ F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result,
+ {
self.result = self.result.and_then(|_| {
if self.is_pretty() {
if self.fields == 0 {
@@ -322,12 +347,12 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> {
let mut slot = None;
let mut state = Default::default();
let mut writer = PadAdapter::wrap(self.fmt, &mut slot, &mut state);
- value.fmt(&mut writer)?;
+ value_fmt(&mut writer)?;
writer.write_str(",\n")
} else {
let prefix = if self.fields == 0 { "(" } else { ", " };
self.fmt.write_str(prefix)?;
- value.fmt(self.fmt)
+ value_fmt(self.fmt)
}
});
@@ -384,7 +409,10 @@ struct DebugInner<'a, 'b: 'a> {
}
impl<'a, 'b: 'a> DebugInner<'a, 'b> {
- fn entry(&mut self, entry: &dyn fmt::Debug) {
+ fn entry_with<F>(&mut self, entry_fmt: F)
+ where
+ F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result,
+ {
self.result = self.result.and_then(|_| {
if self.is_pretty() {
if !self.has_fields {
@@ -393,13 +421,13 @@ impl<'a, 'b: 'a> DebugInner<'a, 'b> {
let mut slot = None;
let mut state = Default::default();
let mut writer = PadAdapter::wrap(self.fmt, &mut slot, &mut state);
- entry.fmt(&mut writer)?;
+ entry_fmt(&mut writer)?;
writer.write_str(",\n")
} else {
if self.has_fields {
self.fmt.write_str(", ")?
}
- entry.fmt(self.fmt)
+ entry_fmt(self.fmt)
}
});
@@ -474,7 +502,20 @@ impl<'a, 'b: 'a> DebugSet<'a, 'b> {
/// ```
#[stable(feature = "debug_builders", since = "1.2.0")]
pub fn entry(&mut self, entry: &dyn fmt::Debug) -> &mut Self {
- self.inner.entry(entry);
+ self.inner.entry_with(|f| entry.fmt(f));
+ self
+ }
+
+ /// Adds a new entry to the set output.
+ ///
+ /// This method is equivalent to [`DebugSet::entry`], but formats the
+ /// entry using a provided closure rather than by calling [`Debug::fmt`].
+ #[unstable(feature = "debug_closure_helpers", issue = "117729")]
+ pub fn entry_with<F>(&mut self, entry_fmt: F) -> &mut Self
+ where
+ F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result,
+ {
+ self.inner.entry_with(entry_fmt);
self
}
@@ -604,7 +645,20 @@ impl<'a, 'b: 'a> DebugList<'a, 'b> {
/// ```
#[stable(feature = "debug_builders", since = "1.2.0")]
pub fn entry(&mut self, entry: &dyn fmt::Debug) -> &mut Self {
- self.inner.entry(entry);
+ self.inner.entry_with(|f| entry.fmt(f));
+ self
+ }
+
+ /// Adds a new entry to the list output.
+ ///
+ /// This method is equivalent to [`DebugList::entry`], but formats the
+ /// entry using a provided closure rather than by calling [`Debug::fmt`].
+ #[unstable(feature = "debug_closure_helpers", issue = "117729")]
+ pub fn entry_with<F>(&mut self, entry_fmt: F) -> &mut Self
+ where
+ F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result,
+ {
+ self.inner.entry_with(entry_fmt);
self
}
@@ -774,6 +828,18 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
/// ```
#[stable(feature = "debug_map_key_value", since = "1.42.0")]
pub fn key(&mut self, key: &dyn fmt::Debug) -> &mut Self {
+ self.key_with(|f| key.fmt(f))
+ }
+
+ /// Adds the key part of a new entry to the map output.
+ ///
+ /// This method is equivalent to [`DebugMap::key`], but formats the
+ /// key using a provided closure rather than by calling [`Debug::fmt`].
+ #[unstable(feature = "debug_closure_helpers", issue = "117729")]
+ pub fn key_with<F>(&mut self, key_fmt: F) -> &mut Self
+ where
+ F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result,
+ {
self.result = self.result.and_then(|_| {
assert!(
!self.has_key,
@@ -788,13 +854,13 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
let mut slot = None;
self.state = Default::default();
let mut writer = PadAdapter::wrap(self.fmt, &mut slot, &mut self.state);
- key.fmt(&mut writer)?;
+ key_fmt(&mut writer)?;
writer.write_str(": ")?;
} else {
if self.has_fields {
self.fmt.write_str(", ")?
}
- key.fmt(self.fmt)?;
+ key_fmt(self.fmt)?;
self.fmt.write_str(": ")?;
}
@@ -838,16 +904,28 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
/// ```
#[stable(feature = "debug_map_key_value", since = "1.42.0")]
pub fn value(&mut self, value: &dyn fmt::Debug) -> &mut Self {
+ self.value_with(|f| value.fmt(f))
+ }
+
+ /// Adds the value part of a new entry to the map output.
+ ///
+ /// This method is equivalent to [`DebugMap::value`], but formats the
+ /// value using a provided closure rather than by calling [`Debug::fmt`].
+ #[unstable(feature = "debug_closure_helpers", issue = "117729")]
+ pub fn value_with<F>(&mut self, value_fmt: F) -> &mut Self
+ where
+ F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result,
+ {
self.result = self.result.and_then(|_| {
assert!(self.has_key, "attempted to format a map value before its key");
if self.is_pretty() {
let mut slot = None;
let mut writer = PadAdapter::wrap(self.fmt, &mut slot, &mut self.state);
- value.fmt(&mut writer)?;
+ value_fmt(&mut writer)?;
writer.write_str(",\n")?;
} else {
- value.fmt(self.fmt)?;
+ value_fmt(self.fmt)?;
}
self.has_key = false;
@@ -935,3 +1013,44 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
self.fmt.alternate()
}
}
+
+/// Implements [`fmt::Debug`] and [`fmt::Display`] using a function.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(debug_closure_helpers)]
+/// use std::fmt;
+///
+/// let value = 'a';
+/// assert_eq!(format!("{}", value), "a");
+/// assert_eq!(format!("{:?}", value), "'a'");
+///
+/// let wrapped = fmt::FormatterFn(|f| write!(f, "{:?}", &value));
+/// assert_eq!(format!("{}", wrapped), "'a'");
+/// assert_eq!(format!("{:?}", wrapped), "'a'");
+/// ```
+#[unstable(feature = "debug_closure_helpers", issue = "117729")]
+pub struct FormatterFn<F>(pub F)
+where
+ F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result;
+
+#[unstable(feature = "debug_closure_helpers", issue = "117729")]
+impl<F> fmt::Debug for FormatterFn<F>
+where
+ F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ (self.0)(f)
+ }
+}
+
+#[unstable(feature = "debug_closure_helpers", issue = "117729")]
+impl<F> fmt::Display for FormatterFn<F>
+where
+ F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ (self.0)(f)
+ }
+}
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index fc91d1afc..e1b7b46a1 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -39,6 +39,9 @@ pub enum Alignment {
#[stable(feature = "debug_builders", since = "1.2.0")]
pub use self::builders::{DebugList, DebugMap, DebugSet, DebugStruct, DebugTuple};
+#[unstable(feature = "debug_closure_helpers", issue = "117729")]
+pub use self::builders::FormatterFn;
+
/// The type returned by formatter methods.
///
/// # Examples
@@ -239,6 +242,7 @@ impl<W: Write + ?Sized> Write for &mut W {
/// documentation of the methods defined on `Formatter` below.
#[allow(missing_debug_implementations)]
#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_diagnostic_item = "Formatter"]
pub struct Formatter<'a> {
flags: u32,
fill: char,
@@ -791,8 +795,10 @@ pub trait Octal {
/// assert_eq!(format!("l as binary is: {l:b}"), "l as binary is: 1101011");
///
/// assert_eq!(
-/// format!("l as binary is: {l:#032b}"),
-/// "l as binary is: 0b000000000000000000000001101011"
+/// // Note that the `0b` prefix added by `#` is included in the total width, so we
+/// // need to add two to correctly display all 32 bits.
+/// format!("l as binary is: {l:#034b}"),
+/// "l as binary is: 0b00000000000000000000000001101011"
/// );
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs
index d37888c27..5bf221b42 100644
--- a/library/core/src/fmt/rt.rs
+++ b/library/core/src/fmt/rt.rs
@@ -133,6 +133,10 @@ impl<'a> Argument<'a> {
Self::new(x, USIZE_MARKER)
}
+ // FIXME: Transmuting formatter in new and indirectly branching to/calling
+ // it here is an explicit CFI violation.
+ #[allow(inline_no_sanitize)]
+ #[no_sanitize(cfi, kcfi)]
#[inline(always)]
pub(super) fn fmt(&self, f: &mut Formatter<'_>) -> Result {
(self.formatter)(self.value, f)