Turbopack: turbofmt/turbobail macros (#90092)
# What
Add turbofmt! and turbobail! proc macros for async string formatting
with Vc<T> and ResolvedVc<T> values.
A new, agent-friendly `FORMATTING.md` file is added to help agents
figure out how these macros work.
# Why
Formatting strings that include turbo-tasks values currently requires
manually .await?ing each Vc, then calling format!, then converting to
RcStr via .into(). By using macros, we can reduce a lot of boilerplate
and potentially offer some opportunities for optimizations by reducing
intermediate, throwaway tasks.
# How
We make use of the "auto-deref" pattern in Rust to choose the "best"
formatting option: ValueToString or Display.
- Zero-alloc FormatIter: A shared iterator parser over format strings
(RawString, EscapedBrace, VarRef, VarRefFormat) that both macros and the
derive use, replacing duplicated manual parsing.
- Borrow-based capture: turbofmt! uses async { .. } (not async move), so
non-Copy types like FileSystemPath can be used in multiple turbofmt!
calls without cloning.
- Debug on StringifyType: Enables {:?} format specs in turbofmt!.
- Converted ~30 call sites across next-core, turbo-tasks-fs,
turbopack-core, turbopack-ecmascript, and others.
# What's Left
- Constants cannot be formatted with turbofmt! yet because of arcane
Rust hygiene rules (similar issue to
https://github.com/rust-lang/rust/issues/131446)
- rust-analyzer doesn't show these format strings as "real" format
strings yet because of limitations of the analyzer, but this should be
possible to make work.
- Automatic derive for ValueToStringRef to avoid intermediate tasks in a
few places where formatting is trivial
- turbowrite!/turbowriteln! could clean up a bit more code