Repository navigation
Open
Labels
C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCCategory: An issue tracking the progress of sth. like the implementation of an RFCT-libsRelevant to the library team, which will review and decide on the PR/issue.Relevant to the library team, which will review and decide on the PR/issue.
Description
Feature gate: #![feature(formatting_options)]
This is a tracking issue for fmt::FormattingOptions.
FormattingOptions can be used to construct custom Formatters at runtime.
Public API
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct FormattingOptions { … }
enum Sign {
Plus,
Minus
}
impl FormattingOptions {
pub fn new() -> Self;
pub fn sign(&mut self, sign: Option<Sign>) -> &mut Self;
pub fn zero_pad(&mut self, zero_pad: bool) -> &mut Self;
pub fn alternate(&mut self, alternate: bool) -> &mut Self;
pub fn fill(&mut self, fill: Option<char>) -> &mut Self;
pub fn alignment(&mut self, alignment: Option<Alignment>) -> &mut Self;
pub fn width(&mut self, width: Option<usize>) -> &mut Self;
pub fn precision(&mut self, precision: Option<usize>) -> &mut Self;
pub fn get_sign(&self) -> Option<Sign>;
pub fn get_zero_pad(&self) -> bool;
pub fn get_alternate(&self) -> bool;
pub fn get_fill(&self) -> Option<char>;
pub fn get_alignment(&self) -> Option<Alignment>;
pub fn get_width(&self) -> Option<usize>;
pub fn get_precision(&self) -> Option<usize>;
pub fn create_formatter<'a>(self, write: &'a mut (dyn Write + 'a)) -> Formatter<'a>;
}
impl<'a> Formatter<'a> {
pub fn new(write: &'a mut (dyn Write + 'a), options: FormattingOptions) -> Self;
pub fn with_options(&mut self, options: FormattingOptions) -> Self;
pub fn sign(&self) -> Option<Sign>;
pub fn options(&self) -> FormattingOptions;
}Steps / History
- API change proposal (ACP)1: [ACP] Provide an interface for creating instances of fmt::Formatter libs-team#286
- Implementation: Implementation of
fmt::FormattingOptions#118159 - Final comment period (FCP)2
- Stabilization PR
Unresolved Questions
- Should this expose the "debug as hex" flags? (
{:x?}and{:X?})
Footnotes
Reacted by Johannes Dahlström, Diana, Taylor Cramer, Chaoses-Ib, Juhan Oskar Hennoste, bugRanger, stefnotch, TuxCoder, Samuel Colvin, David James and 6 more
Reacted by Gabriel Bjørnager Jensen, Taylor Cramer, Juhan Oskar Hennoste, bugRanger, Antonin Delpeuch, Ashish Myles and Thayne McCombs
Reacted by Ruby Lazuli, CosminPerRam, Taylor Cramer, Juhan Oskar Hennoste, bugRanger, Henrik Gustafsson, Ivan Sotnikov and Thayne McCombs
Metadata
Metadata
Assignees
Labels
C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCCategory: An issue tracking the progress of sth. like the implementation of an RFCT-libsRelevant to the library team, which will review and decide on the PR/issue.Relevant to the library team, which will review and decide on the PR/issue.
Activity
EliasHolzmann commentedon Nov 21, 2023
@rustbot claim
[-]Tracking Issue for XXX[/-][+]Tracking Issue for `FormattingOptions`[/+]Auto merge of rust-lang#118159 - EliasHolzmann:formatting_options, r=…
Auto merge of rust-lang#118159 - EliasHolzmann:formatting_options, r=…
Auto merge of rust-lang#118159 - EliasHolzmann:formatting_options, r=…
Auto merge of rust-lang#118159 - EliasHolzmann:formatting_options, r=…
joboet commentedon Jan 22, 2025
I was wondering: could the signature for
Formatter::newbe changed to take a reference to theFormattingOptionsinstead of passing them by value? That way, LLVM wouldn't need to copy around the options as often, which seems like it could improve performance and binary size in cases where the same options are used multiple times, for instance when using the default options.Rollup merge of rust-lang#135977 - nyurik:fix-fmt-options, r=joboet
Rollup merge of rust-lang#135977 - nyurik:fix-fmt-options, r=joboet
Unrolled build for rust-lang#135977
EliasHolzmann commentedon Jan 25, 2025
@joboet I don't think so.
Formatterdirectly holds aFormattingOptionsinternally: https://doc.rust-lang.org/nightly/src/core/fmt/mod.rs.html#524If
Formatter::newtakes itsFormattingOptionsby reference instead of by value, we'd have to copy the options in that function anyway. (Instead, you probably could have the contents ofFormattingOptionsbehind aRcso that copying/cloning is cheaper, which might indeed improve performance for use cases with heavyFormattingOptionsreuse. However, I don't think that this will compensate the ref-counting overhead that is in most use cases probably unnecessary.)In most cases, when the
FormattingOptionscan be used multiple times, the target buffer of the resultingFormatteris probably also the same – in this case, you can just use theFormatteryou construct.Auto merge of rust-lang#136862 - joboet:formatter_options_ref, r=<try>
6 remaining items
formatting_options: Make all methods `const`
formatting_options: Make all methods `const`
formatting_options: Make all methods `const`
TechPizzaDev commentedon Aug 26, 2025
FormattingOptionswas 3x pointer size last I checked, which is why I found theCopyderive strange.There was discussion to pack it down, but that would be annoying if any new fields were to be added in the future.
Rollup merge of rust-lang#145863 - EliasHolzmann:formatting_options_2…
Unrolled build for #145863
formatting_options: Make all methods `const`
Rollup merge of rust-lang#145863 - EliasHolzmann:formatting_options_2…
theemathas commentedon Feb 13, 2026
I and @SabrinaJewson found that, with
Formatter::new(), it's possible to substitute a differentFormatterin aDebugimpl, causing the rest of the surroundingDebugimpl write to a different place. For example:Output:
Also, changing the
{:?}to{:#?}causes the program to output a single comma:jhpratt commentedon Feb 13, 2026
Short of changing the lifetime to be invariant, which would probably be a breaking change(?), I'm not sure what could be done about that. Assuming we want to keep
Formatter::new, of course.SabrinaJewson commentedon Feb 13, 2026
The lifetime is already invariant, so that wouldn’t help anything – the only solution would be to disallow constructing
Formatters entirely. But this seems highly unlikely to break anything unless the user is really trying to break it, and it doesn’t seem to produce unsoundness either like&mut ReadBufdid. If we really did need to fix it:EliasHolzmann commentedon Feb 13, 2026
This is indeed an interesting edge case, thanks for pointing that out, I didn't think about that.
In theory, if you e.g. debug output some type from a sketchy dependency that does funny business, that could redirect your output to somewhere else, which might take you a while to figure out. But if you run untrusted code, you've got bigger problems than that. All in all, I have to agree with Sabrina that this doesn't really break anything in practice. And while I'm not familiar with the problems around
&mut ReadBuf, there is nounsafeinFormattingOptions, so I don't see how it coild lead to unsoundness (assuming the soundness of safe Rust, of course).vitu168 commentedon May 14, 2026