`op_result` - thin proc macro sugar for std operator trait bounds

⚓ Rust    📅 2025-11-10    👤 surdeus    👁️ 2      

surdeus

Have 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_result transforms a generic function, turning "operator bound expressions" (e.g. [(); T + U]:, (): IsDefined<{ T + U }> into trait bound syntax. This can be combined seamlessly with output! 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

Read full topic

🏷️ Rust_feed