Implement builder or macro for easier context creation
I think it would be nice to have a builder or a macro for creating a context in one expression like this:
//builder
let ctx = ContextBuilder::new()
.with("...", ...)
.with("...", ...);
//macro
let ctx = context! {
... => ...,
... => ...,
};
//current syntax
let mut ctx = Context::new();
ctx.insert("...", ...);
ctx.insert("...", ...);
I like the idea. Rocket does also provide a context macro for tera. I like the rocket syntax even more.
let context = context! {
// Note that shorthand field syntax is supported.
// This is equivalent to `foo: foo,`
foo,
bar: "Hello world",
}
let context = context! {cargo_pkg_version: CARGO_PKG_VERSION, cargo_pkg_name: CARGO_PKG_NAME, style}
https://api.rocket.rs/master/rocket_dyn_templates/macro.context.html
This is much shorter and easier to read as the insert alternatives.
I don't like the builder pattern but the macro approach could work.
I have a macro that I developed for my own use that you can feel free to adopt. There's no need to bring serde into the mix like Rocket does, as Context::insert is even easlier to work with.
Happy to license it as needed for this project -- it's pretty trivial code. It allows four styles of context definition, which can be mixed and matched, and correctly handles extraneous trailing commas:
context! {
id, /* Use value and type from variable in scope */
id: type, /* Use value from variable in scope, force type resolution */
id = expression, /* Use automatic type inference from expression */
id: type = expression, /* Use forced type and expression */
}
https://github.com/mmastrac/progscrape/blob/87d0a877da4f6101e429e8028f8aa04cd85fc2a6/web/src/web.rs#L307
macro_rules! context_assign {
($id:ident , ,) => {};
($id:ident , , $typ:ty) => {
let $id: $typ = $id;
};
($id:ident , $expr:expr , $typ:ty) => {
let $id: $typ = $expr;
};
($id:ident , $expr:expr ,) => {
let $id = $expr;
};
}
macro_rules! context {
( $($id:ident $(: $typ:ty)? $(= $expr:expr)? ),* $(,)? ) => {
{
let mut context = Context::new();
// Create a local variable for each item of the context, with a type if specified.
$(
context_assign!($id , $($expr)? , $($typ)?);
context.insert(stringify!($id), &$id);
)*
context
}
};
}