A procedural attribute macro to reduce boilerplate when writing functions that partially borrow a struct.
Overview
Annotating a struct Mystruct with #[clasma], allows the attribute proc-macro #[partial(Mystruct)] on a function foo, to generate a macro foo!, that is callable similarly to foo, except that one can pass an instance of Mystruct to provide the arguments in foo that correspond to Mystruct's fields.
This crate attempts to make partial or "split" borrows more ergonomic in Rust, where functions sometimes must borrow individual fields, rather than a single mutable reference to a struct, in order to adhere to borrowing rules, leading to verbose call sites.
Usage
Consider the following struct:
let mut mystruct = Mystruct ;
The clasma::partial attribute proc-macro generates a macro foo!. The first argument to the foo! is mystruct. foo! borrows each of mystruct's fields individually, matching foo's argument names. One passes the remaining arguments in the same order as the signature.
foo!;
// expands to:
// foo(&mut mystruct.a, &mystruct.b, 3);
One can reorder arguments; they just have to match with the struct's fields. One can also optionally provide generic parameters inside angle brackets <...>.
foo!;
// expands to:
// foo::<&str>(&mystruct.b, "hello", &mut mystruct.a, &mystruct.c);
Lifetime parameters are also supported.
const mystruct: Mystruct = Mystruct ;
foo!;
// expands to:
// foo::<'static>(&mystruct.b, &mystruct.a, &3);
Propagating from scope
Two functions marked with identical clasma::partial attributes, can call one another using <function name>_scope! macros. One calls foo_scope! identically to foo!, except that one omits the mystruct. The arguments to foo previously supplied by mystruct, now come directly from the local scope at the call site.
impl-blocks
For impl blocks, the #[partial(..)] attribute goes on top of the impl. This will generate macros for all functions in the block.
foo!;
// expands to:
// Mystruct::foo(&mut mystruct.a, &mystruct.b, 3);
If both the type and the function in the impl block are generic, one can provide the arguments separated by :: like so:
foo!;
// expands to:
// Mystruct::<&str>::foo::<u8>(&mut mystruct.a, &mystruct.b, 3, "hello");
If only the type is generic, one passes the arguments like this: foo!(<T>::, mystruct, ...)
Motivating Example
Imagine a Tourist with a list of travel destinations, that counts the number of times he visits one of his destinations.
Before
Without partial borrowing, this code does not compile.
The issue is that visit unnecessarily borrows self.destinations mutably when it only needs an immutable borrow. A workaround would be to borrow each struct field separately on every call to visit:
However, this gets tedious as the number of fields increases.
With clasma::partial
The partial macro handles borrowing and argument passing.
Installation