-
-
Notifications
You must be signed in to change notification settings - Fork 14.3k
Description
Right now format_args! uses, e.g. ArgumentV1::new(&runtime_data, Debug::fmt) (for {:?}), at runtime, using up two pointers per argument at runtime instead of just one (&runtime_data).
With allow_internal_unsafe and #44240, we can place the (e.g. Debug::fmt) fn pointers in (rvalue-promoted) 'static data, the remaining hurdle is how to infer the type of the runtime data.
That is, Debug::fmt is really <_ as Debug>::fmt and that _ is right now inferred because of ArgumentV1::new's signature typing them together. If they're separate, we need something new.
I propose using the HList pattern (struct HCons<H, T>(H, T); struct HNil; - so for 3 elements, of types A, B and C you'd have HCons<A, HCons<B, HCons<C, HNil>>>), with #[repr(C)], which would give it a deterministic layout which matches that of an array, that is, these two:
&'static HCons<fn(&A), HCons<fn(&B), HCons<fn(&C), HNil>>>&'static [unsafe fn(*const Opaque); 3]
have the same representation, and the latter can be unsized into a slice. This transformation from HList to array (and then slice) can be performed on top of a safe, rvalue-promoted HCons, which is a necessary requirement for moving the fn pointers into 'static data at all.
For inference, we can simply insert some function calls to match up the types, e.g. to infer B we could dofmt::unify_fn_with_data((list.1).0, &b), which would makeB into typeof b.
It might actually be simpler to have a completely safe "builder" interface, which combines the HList of formatters with a HList of runtime references, unifying the types, but I'm a bit worried about compile-times due to all the trait dispatch - in any case, the impact should be measured.