Skip to content
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

Add crate documentation and update README #38

Merged
merged 5 commits into from
Oct 15, 2018
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
214 changes: 24 additions & 190 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,216 +1,50 @@
# `auto_impl` [![Join the chat at https://gitter.im/auto-impl-rs/Lobby](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/auto-impl-rs/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status](https://travis-ci.org/auto-impl-rs/auto_impl.svg?branch=master)](https://travis-ci.org/auto-impl-rs/auto_impl) [![Crates.io](https://img.shields.io/crates/v/auto_impl.svg)](https://crates.io/crates/auto_impl)
# `auto_impl` [![Join the chat at https://gitter.im/auto-impl-rs/Lobby](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/auto-impl-rs/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status](https://travis-ci.org/auto-impl-rs/auto_impl.svg?branch=master)](https://travis-ci.org/auto-impl-rs/auto_impl) [![Crates.io](https://img.shields.io/crates/v/auto_impl.svg)](https://crates.io/crates/auto_impl) [![docs](https://docs.rs/auto_impl/badge.svg)](https://docs.rs/auto_impl)

A simple compiler plugin for automatically implementing a trait for some common smart pointers and closures.
A proc-macro attribute for automatically implementing a trait for references,
some common smart pointers and closures.

# Usage

This library requires the `nightly` channel.
This library requires Rust 1.30.0 or newer.

Add `auto_impl` to your `Cargo.toml`:

```
auto_impl = "*"
```

Reference in your crate root:
Add `auto_impl` to your `Cargo.toml` and just use it in your crate:

```rust
#![feature(proc_macro)]

extern crate auto_impl;

// In Rust 2015 you still need `extern crate auto_impl;` at your crate root
use auto_impl::auto_impl;
```

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 `Box`

```rust
#[auto_impl(Box)]
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;
fn execute3(self) -> Self::Type1;
fn execute4() -> &'static str;
}
```

Will expand to:

```rust
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).execute1(arg1)
}

fn execute2(&self) -> Self::Type2 {
(**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;
}
```

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).execute1(arg1)
}

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

impl<'a, T, TAutoImpl> MyTrait<'a, T> for ::std::rc::Rc<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).execute1(arg1)
}

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

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

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

## Implement a trait for a closure
Add an `auto_impl` attribute to traits you want to automatically implement for wrapper types. Here is a small example:

```rust
#[auto_impl(Fn)]
trait MyTrait<'a, T> {
fn execute<'b>(&'a self, arg1: &'b T, arg2: &'static str) -> Result<(), String>;
// This will generate two additional impl blocks: one for `&T` and one
// for `Box<T>` where `T: Foo`.
#[auto_impl(&, Box)]
trait Foo {
fn foo(&self);
}
```

Will expand to:

```rust
impl<'a, T, TAutoImpl> MyTrait<'a, T> for TAutoImpl
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)
}
impl Foo for i32 {
fn foo(&self) {}
}
```

There are a few restrictions on `#[auto_impl]` for closures. The trait must:
fn requires_foo(_: impl Foo) {}

- Have a single method
- Have no associated types
- Have no non-static lifetimes in the return type

## Implement a trait for a borrowed reference

```rust
#[auto_impl(&, &mut)]
trait MyTrait<'a, T> {
fn execute<'b>(&'a self, arg1: &'b T, arg2: &'static str) -> Result<(), String>;
}
requires_foo(0i32); // works: through the impl we defined above
requires_foo(&0i32); // works: through the generated impl
requires_foo(Box::new(0i32)); // works: through the generated impl
```

Will expand to:
For more explanations, please see [**the documentation**](https://docs.rs/auto_impl) and for more examples, see [the examples folder](https://github.com/auto-impl-rs/auto_impl/tree/master/examples).

```rust
impl<'auto, 'a, T, TAutoImpl> MyTrait<'a, T> for &'auto TAutoImpl {
fn execute<'b>(&'a self, arg1: &'b T, arg1: &'static str) -> Result<(), String> {
(**self).execute(arg1, arg2)
}
}

impl<'auto, 'a, T, TAutoImpl> MyTrait<'a, T> for &'auto mut TAutoImpl {
fn execute<'b>(&'a self, arg1: &'b T, arg1: &'static str) -> Result<(), String> {
(**self).execute(arg1, arg2)
}
}
```
---

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

- Only have methods that take `&self` or have no receiver (static)
Licensed under MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT).

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

- Only have methods that take `&self`, `&mut self` or have no receiver (static)
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you shall be licensed as above, without any additional terms or conditions.
14 changes: 14 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Examples

- `error_messages`: contains some incorrect code that showcases the error messages emitted by `auto_impl`
- **`greet_closure`**: simple example showing how to auto impl for `Fn` traits
- **`keep_default_for`**: shows how to use the `#[auto_impl(keep_default_for(...))]` attribute
- `names`: showcases how `auto_impl` chooses new ident names
- **`refs`**: shows how to auto impl for `&` and `Box`


**Note**: if you want to see what the generated impl blocks look like, use the execellent [`cargo expand`](https://github.com/dtolnay/cargo-expand):

```
$ cargo expand --example refs
```
Loading