Skip to content

Commit

Permalink
Merge pull request #38 from LukasKalbertodt/docs
Browse files Browse the repository at this point in the history
Add crate documentation and update README
  • Loading branch information
LukasKalbertodt authored Oct 15, 2018
2 parents e285cd7 + 7d44b6c commit b15c579
Show file tree
Hide file tree
Showing 7 changed files with 282 additions and 191 deletions.
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

0 comments on commit b15c579

Please sign in to comment.