How to allow arbitrary expressions in format strings

Yeah, strong plus one here! To expand on this, it's important that we allow API like the following

use std::process::Command;

fn build_cmd(interpolated: InterpolatedArgs<???>) -> Command {
    ....
}

let branch = "my branch"
let cmd = build_cmd(i"git switch {branch}");
assert_eq!(cmd.get_args.count(), 3);

It should be possible to implement build_cmd in a way that is not susceptible to shell injection. The problem is, I don't think we currently can spell-out a type for InterpolatedArgs.

It's useful to take a look at JS here. They did the right thing here with tagged templates. When you write, in JS,

i`select from ${foo()} where id = ${bar};` 

The user-defined i function gets called roughly as i(["select from ", "where id =", ";"], [foo(), bar]). That is, the user gets to apply custom escaping rules when processing the string.

The problem is, the second argument here is a heterogeneous list :frowning: To support this in Rust, we need a language machinery to define InterpolatedArgs<Ts...> and to define where-clauses like where Ts...: SqlEscape.

Today's format args work because they are specialized to one particular trait fmt::Display and use dynamic dispatch.

I sadly don't see how we can solve a very practical problem of allowing injection-prof APIs without advanced type machinery :frowning: And yeah, there is a danger that, by making string interpolation convenient enough without providing a more general mechanism as well, we'll end up with people using interpolation for things like SQL or HTML building.

12 Likes