Stabilising Formatter::flags


#1

cf: https://github.com/rust-lang/rust/pull/24492

I started refactoring some of the innards of core::fmt, which then resulted in realising that some chunks of user facing code in fmt_macros will need tweaking.

My strawman is that the underlying flags should be expressed as an explicit bitmap, but not exposed to the users, instead a series of getters and setters would exposed on Formatter. The remaining question to my mind is whether the api should explicitly create an accessor for each field in the bitset, eg

fmter.flags.is_alternate() -> bool
fmter.flags.set_alternate(true)

Or a single method and an enum for the flags:

fmter.flags.get(Flag::Alternate) -> bool
fmter.flags.set(Flag::Alternate)
fmter.flags.unset(Flag::Alternate)

My preference is the second, but I would appreciate feedback.

Finally, the implementation of fmt::Pointer requires saving and resetting the flags. My belief is that this shoudl return an opaque wrapper for the underlying storage:

struct RawFlags(u32);
let raw = fmter.flags.get_raw() // -> RawFlags;
fmter.set_raw(raw)

Feedback would definitely be appreciated though.

richo


#2

Apologies for not responding directly to your question, but…

I started refactoring some of the innards of core::fmt…

I’m curious about this, as I have an heavily optimized version of core::fmt that I’ve been meaning to post about at some point.

Briefly: My approach was to move as much information as possible into an ArgumentsSpec structure, including the address of the type-specific fmt function. A generated ArgumentsSpec can’t be specified as a static or const item because its value depends on local types, but the compiler allocates it statically anyway. My other change was to specify formatting parameters using a FormattedArg wrapper, so that fmt::write's run-time work becomes trivial. There are extensive changes in libsyntax. It works and passes tests, although it’s currently limited to 32 parameters. I don’t have precise measurements, but it makes various rustc crates 1-3% smaller or so.

My strawman is that the underlying flags should be expressed as an explicit bitmap, but not exposed to the users, instead a series of getters and setters would exposed on Formatter.

Part of my optimization relies on Formatter being immutable, though. As long as it can’t be changed, then Formatter can use an optional reference to the format parameters, which in the default, typical case, is a single pointer initialized to NULL. I changed Pointer to generate a new Formatter wrapping the previous one.

(Correction: Pointer's new Formatter doesn’t wrap the previous Formatter. Rather, it borrows the existing Formatter's Write trait object and copies the previous formatter parameters, if any exist.)


#3

As it stands, the Formatter is mutable (This is encoded in the signature of the various fmt:: traits).

I’d be interested in trying to work on top of what you’ve got if this goes ahead, however the assumption that the Formatter is immutable seems like a non starter, I’m interested in stabilising some subtle aspects of the API, whereas this would largely break what’s already public.


#4

By “immutable”, I suppose I meant that the formatting flags on Formatter are immutable. My version doesn’t break anything public, other than formats with more than 32 parameters, which I believe is fixable.

I think making the flags mutable requires allocating them in the Formatter. Maybe it’d slow down its initialization, but maybe it’s worth it for a nicer API.