Skip to content

Commit

Permalink
Merge pull request #6 from KodrAus/feat/by-value-and-static-methods
Browse files Browse the repository at this point in the history
Support by-value and static methods where possible
  • Loading branch information
KodrAus authored Oct 9, 2017
2 parents 53a2e89 + ae5056a commit 29fbb00
Show file tree
Hide file tree
Showing 7 changed files with 382 additions and 158 deletions.
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 <ashleymannix@live.com.au>"]
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

0 comments on commit 29fbb00

Please sign in to comment.