`op_result` - thin proc macro sugar for std operator trait bounds
⚓ Rust 📅 2025-11-10 👤 surdeus 👁️ 2Have you ever tried to write generic code to a std::ops contract and been frustrated at the verbosity?
fn compute_nested<T, U, V>(a: T, b: U, c: V) -> <<<T as Add<U>>::Output as Add<V>>::Output
where
T: Add<U>,
<<T as Add<U>>::Output: Add<V>
{
a + b + c
}
Introducing op_result - a thin proc macro language extension to make op trait bounds palatable:
use op_result::op_result;
use op_result::output;
#[op_result]
fn compute_nested<T, U, V>(a: T, b: U, c: V) -> output!(T + U + V)
where
[(); T + U]:,
[(); output!(T + U) + V]:,
// or, equivalently, with "marker trait notation"
(): IsDefined<{ T + U }>,
(): IsDefined<{ output!(T + U) + V }>,
{
a + b + c
}
// we can even assign output types!
fn compute_with_assignment<T, U, V>(a: T, b: U) -> V
where
[(); T + U = V]:,
{
a + b
}
op_result introduces two macros:
-
output!transforms an "operator output expression" into associated type syntax, and can be used flexibly in where bounds, generic parameter lists, and return types -
op_resulttransforms a generic function, turning "operator bound expressions" (e.g.[(); T + U]:,(): IsDefined<{ T + U }>into trait bound syntax. This can be combined seamlessly withoutput!to consistently and readably express complex operator bounds for generic functions.
This works with any std::op that has an associated Output type, and comes complete with span manipulation to provide docs on hover.
Happy coding!
2 posts - 2 participants
🏷️ Rust_feed