I've just published an initial release for auto_impl
, a nightly
compiler plugin for automatically implementing a trait for some common smart pointers and closure traits.
You add an #[auto_impl(...)]
attribute to a trait to have it implement for a wrapper. There's some more detail in the readme.
Looks like:
#[auto_impl(Fn)] // <- `auto_impl` for `Fn(GetProduct) -> Result<GetProductResult, QueryError>
pub trait GetProductQuery {
fn get_product(&self, query: GetProduct) -> Result<GetProductResult, QueryError>;
}
// Means we can return a closure as `impl GetProductQuery`
pub fn get_product_query<TStore>(store: TStore) -> impl GetProductQuery
where TStore: ProductStore
{
move |query: GetProduct| {
let ProductData { id, title, .. } = store.get(query.id)?.ok_or("not found")?.into_data();
Ok(GetProductResult {
id: id,
title: title
})
}
}
Or:
#[auto_impl(Arc)] // <- `auto_impl` for `Arc<T: ProductStore>`
pub trait ProductStore {
fn get(&self, id: i32) -> Result<Option<Product>, Error>;
fn set(&self, product: Product) -> Result<(), Error>;
}
pub struct Resolver {
product_store: Arc<InMemoryStore>,
}
impl Resolver {
// Means we can return an `Arc<T>` as `impl ProductStore`
pub fn product_store(&self) -> impl ProductStore {
self.product_store.clone()
}
}
The plugin itself doesn't actually do a whole lot, it started life as a macro for cases where I wanted to reduce a bit of boilerplate but didn't want to logically link some types together through a common trait. I think its use-case is fairly niche but thought it was worth throwing it out in the wild
I've mostly been using it internally, so there are probably cases it doesn't cover well and some obvious enhancements I haven't needed but would be happy to explore.
Feedback is always welcome!