README driven development

I wrote this README as a roadmap for something I'd like to implement, but I don't have the time and regardless I'd love to be told why it's impossible or a bad idea, anyway. I'm posting it here, but I thought it would be fun to invite the community to share readmes for crates they never published, as well. So here's mine:

keyword_arguments

keyword_arguments lets you use keyword arguments to call functions. It does this by using a function's signature to generate a parameter object as an input to the function and a matching macro to call that function with that parameter object.

There are three parts to this:

  1. It defines a parameter object for a given function. This is a predictably named struct that you can implement traits on.
  2. It defines a parametrized function that uses the parameter object as its single argument.
  3. It defines a declarative macro for calling the parametrized function with the original name.

For example:

#[keyword_arguments::parametrize]
fn add(a: i32, b: i32) -> i32 {
    a + b
};

Which generates a declarative macro add! which you can call with keywords instead of positional arguments:

fn main() {
    let a_then_b = add!(a: 1, b: 2);
    let b_then_a = add!(b: 1, a: 2);

    assert_eq!(a_then_b, b_then_a); // 3
}

Under the hood, it generates a ParametrizedAdd struct and a parametrized_add function:

struct ParametrizedAdd {
    a: i32,
    b: i32,
}

fn parametrized_add(param: ParametrizedAdd) -> i32 {
    let ParametrizedAdd { a, b } = param;
    add(a, b)
}

Which is useful in case you want to use defaults for your arguments:

#[parametrize(use-defaults = true)]
fn add(a: i32, b: i32) -> i32 {
    a + b
};

impl Default for ParametrizedAdd {
    fn default() -> Self {
        Self {
            a: 1,
            b: 2,
        }
    }
}

fn main() {
    let with_defaults = add!();

    assert_eq!(with_defaults, 3);

    let one_kwarg = add!(b: 100);
    assert_eq!(one_kwarg, 101);
}

Finally, you can tweak the visibility of the generated items like so:

#[parametrize(
    visibility = {
        struct = "pub(crate)",
        macro_export = true
    }
)]
fn add(a: i32, b: i32) -> i32 {
    a + b
};

How would these macros work with rust-analyzer? Using a struct explicitly for named arguments is friendlier in an IDE.

Rust-analyzer runs macros similar to how rustc does it so from its point of view there will be no macros but all the stuff they generate instead. You won't get much help writing them since they are not a valid rust though.

That's the point. If foo is a function then when I type foo( I get a lot of contextual help, but not so with foo!( as far as I know. For functions with named and default arguments why not use a builder?