rust-lang / impl-trait-utils

Utilities for working with impl traits in Rust.
Apache License 2.0
89 stars 9 forks source link

Create variant macro #2

Closed tmandry closed 9 months ago

tmandry commented 9 months ago

This takes an input like this:

#[variant(SendIntFactory: Send)]
trait IntFactory {
    async fn make(&self, x: u32, y: &str) -> i32;
    fn stream(&self) -> impl Iterator<Item = i32>;
    fn call(&self) -> u32;
}

And creates an additional trait with the specified bounds:

trait SendIntFactory: Send {
    fn make(&self, x: u32, y: &str) -> impl ::core::future::Future<Output = i32> + Send;
    fn stream(&self) -> impl Iterator<Item = i32> + Send;
    fn call(&self) -> u32;
}

And a blanket impl, so the implementer only has to implement one trait:

impl<T> IntFactory for T
where
    T: SendIntFactory,
{
    async fn make(&self, x: u32, y: &str) -> i32 {
        <Self as SendIntFactory>::make(self, x, y).await
    }
    fn stream(&self) -> impl Iterator<Item = i32> {
        <Self as SendIntFactory>::stream(self)
    }
    fn call(&self) -> u32 {
        <Self as SendIntFactory>::call(self)
    }
}

After brainstorming a handful of options I settled on variant as the most self-explanatory name for what this macro does. It does unfortunately conflict with enum variants, but I don't think that will actually be confusing in context.

My hope is that this will be forward-compatible with both RTN and implementable trait aliases, as described here.