Skip to content

Support by-value and static methods where possible #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 9, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "auto_impl"
version = "0.1.2"
version = "0.2.0"
authors = ["Ashley Mannix <[email protected]>"]
license = "MIT"
description = "Automatically implement traits for common smart pointers and closures"
Expand Down
85 changes: 68 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,39 @@ extern crate auto_impl;
use auto_impl::auto_impl;
```

The following types are supported:
Add an `auto_impl` attribute to traits you want to automatically implement for wrapper types:

```rust
#[auto_impl(&, Arc)]
pub trait OrderStoreFilter {
fn filter<F>(&self, predicate: F) -> Result<Iter, Error>
where
F: Fn(&OrderData) -> bool;
}
```

Now anywhere that requires a `T: OrderStoreFilter` will also accept an `&T` or `Arc<T>` where `T` implements `OrderStoreFilter`.

## Specifics

The following types are supported and can be freely combined:

- [`Arc`](https://doc.rust-lang.org/std/sync/struct.Arc.html)
- [`Rc`](https://doc.rust-lang.org/std/rc/struct.Rc.html)
- [`Box`](https://doc.rust-lang.org/std/boxed/struct.Box.html)

The following types are also supported, but require a blanket implementation (you can only have one of these per `trait`):

- [`Fn`](https://doc.rust-lang.org/std/ops/trait.Fn.html)
- [`FnMut`](https://doc.rust-lang.org/std/ops/trait.FnMut.html)
- [`FnOnce`](https://doc.rust-lang.org/std/ops/trait.FnOnce.html)
- `&`
- `&mut`

## Implement a trait for a smart pointer

Add the `#[auto_impl]` attribute to traits to automatically implement them for wrapper types:
## Implement a trait for `Box`

```rust
#[auto_impl(Arc, Box, Rc)]
#[auto_impl(Box)]
trait MyTrait<'a, T>
where T: AsRef<str>
{
Expand All @@ -47,41 +63,74 @@ trait MyTrait<'a, T>

fn execute1<'b>(&'a self, arg1: &'b T) -> Result<Self::Type1, String>;
fn execute2(&self) -> Self::Type2;
fn execute3(self) -> Self::Type1;
fn execute4() -> &'static str;
}
```

Will expand to:

```rust
impl<'a, T, TAutoImpl> MyTrait<'a, T> for ::std::sync::Arc<TAutoImpl>
impl<'a, T, TAutoImpl> MyTrait<'a, T> for ::std::boxed::Box<TAutoImpl>
where TAutoImpl: MyTrait<'a, T>,
T: AsRef<str>
{
type Type1 = TAutoImpl::Type1;
type Type2 = TAutoImpl::Type2;

fn execute1<'b>(&'a self, arg1: &'b T) -> Result<Self::Type1, String> {
self.as_ref().execute1(arg1)
(**self).execute1(arg1)
}

fn execute2(&self) -> Self::Type2 {
self.as_ref().execute2()
(**self).execute2()
}

fn execute3(self) -> Self::Type1 {
(*self).execute3()
}

fn execute4() -> &'static str {
TAutoImpl::execute4()
}
}
```

There are no restrictions on `auto_impl` for `Box`.

## Implement a trait for a smart pointer

Add the `#[auto_impl]` attribute to traits to automatically implement them for wrapper types:

```rust
#[auto_impl(Arc, Rc)]
trait MyTrait<'a, T>
where T: AsRef<str>
{
type Type1;
type Type2;

fn execute1<'b>(&'a self, arg1: &'b T) -> Result<Self::Type1, String>;
fn execute2(&self) -> Self::Type2;
}
```

impl<'a, T, TAutoImpl> MyTrait<'a, T> for Box<TAutoImpl>
Will expand to:

```rust
impl<'a, T, TAutoImpl> MyTrait<'a, T> for ::std::sync::Arc<TAutoImpl>
where TAutoImpl: MyTrait<'a, T>,
T: AsRef<str>
{
type Type1 = TAutoImpl::Type1;
type Type2 = TAutoImpl::Type2;

fn execute1<'b>(&'a self, arg1: &'b T) -> Result<Self::Type1, String> {
self.as_ref().execute1(arg1)
(**self).execute1(arg1)
}

fn execute2(&self) -> Self::Type2 {
self.as_ref().execute2()
(**self).execute2()
}
}

Expand All @@ -93,18 +142,18 @@ impl<'a, T, TAutoImpl> MyTrait<'a, T> for ::std::rc::Rc<TAutoImpl>
type Type2 = TAutoImpl::Type2;

fn execute1<'b>(&'a self, arg1: &'b T) -> Result<Self::Type1, String> {
self.as_ref().execute1(arg1)
(**self).execute1(arg1)
}

fn execute2(&self) -> Self::Type2 {
self.as_ref().execute2()
(**self).execute2()
}
}
```

There are a few restrictions on `#[auto_impl]` for smart pointers. The trait must:

- Only have methods that take `&self`
- Only have methods that take `&self` or have no receiver (static)

## Implement a trait for a closure

Expand All @@ -119,7 +168,7 @@ Will expand to:

```rust
impl<'a, T, TAutoImpl> MyTrait<'a, T> for TAutoImpl
where TAutoImpl: Fn(&T, &'static str) -> Result<(), String>
where TAutoImpl: ::std::ops::Fn(&T, &'static str) -> Result<(), String>
{
fn execute<'b>(&'a self, arg1: &'b T, arg1: &'static str) -> Result<(), String> {
self(arg1, arg2)
Expand Down Expand Up @@ -160,6 +209,8 @@ impl<'auto, 'a, T, TAutoImpl> MyTrait<'a, T> for &'auto mut TAutoImpl {

There are a few restrictions on `#[auto_impl]` for immutably borrowed references. The trait must:

- Only have methods that take `&self`
- Only have methods that take `&self` or have no receiver (static)

There are a few restrictions on `#[auto_impl]` for mutably borrowed references. The trait must:

There are no restrictions on `#[auto_impl]` for mutably borrowed references.
- Only have methods that take `&self`, `&mut self` or have no receiver (static)
15 changes: 15 additions & 0 deletions compile_test/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
/*!
Try running `cargo expand` on this crate to see the output of `#[auto_impl]`.
*/

#![feature(proc_macro)]

extern crate auto_impl;
Expand Down Expand Up @@ -28,6 +32,17 @@ trait RefTrait1<'a, T: for<'b> Into<&'b str>> {
fn execute2(&self) -> Self::Type2;
}

#[auto_impl(Box)]
trait BoxTrait1<'a, T: for<'b> Into<&'b str>> {
type Type1;
type Type2;

fn execute1<'b>(&'a self, arg1: &'b T) -> Result<Self::Type1, String>;
fn execute2(&mut self, arg1: i32) -> Self::Type2;
fn execute3(self) -> Self::Type1;
fn execute4(arg1: String) -> Result<i32, String>;
}

fn main() {
println!("Hello, world!");
}
Loading