disponent 0.2.2

An alternative to dynamic-dispatched method calls, without the need for object safety
Documentation
# `disponent`

[<img alt="github" src="https://img.shields.io/badge/github-explodingcamera/disponent-8da0cb?style=flat-square&labelColor=555555&logo=github" height="20">](https://github.com/explodingcamera/disponent)
[<img alt="crates.io" src="https://img.shields.io/crates/v/disponent.svg?style=flat-square&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/disponent)
[<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-disponent-66c2a5?style=flat-square&labelColor=555555&logo=docs.rs" height="20">](https://docs.rs/disponent)
[<img alt="build status" src="https://img.shields.io/github/actions/workflow/status/explodingcamera/disponent/ci.yaml?branch=main&style=flat-square" height="20">](https://github.com/explodingcamera/disponent/actions?query=branch%3Amain)

`disponent` is an alternative to using `dyn Trait` trait objects for dispatching to multiple implementations of a trait. Works with async methods, generics, `#[cfg]` attributes, `no_std` and even traits that are not object safe.

## Usage

```rust
use disponent::declare;

declare!(
    pub enum FooOrBar {
        Foo(Foo),
        Bar(Bar),
    }

    pub trait SayHello {
        fn say_hello(&self) -> impl Future<Output = ()>;
        fn name(&self) -> &'static str;

        // Default implementations work too
        fn with_default(&self) -> &'static str {
            "default"
        }
    }
);

pub struct Foo;
impl SayHello for Foo {
    async fn say_hello(&self) {
        println!("Hello from Foo")
    }
    fn name(&self) -> &'static str { "Foo" }
}

pub struct Bar;
impl SayHello for Bar {
    async fn say_hello(&self) {
        println!("Hello from Bar")
    }
    fn name(&self) -> &'static str { "Bar" }
}

fn main() {
    // `FooOrBar` implements `SayHello` by delegating to the inner type
    let foo_or_bar = FooOrBar::Foo(Foo);
    smol::block_on(foo_or_bar.say_hello());
    println!("My name is {}", foo_or_bar.name());
}
```

## Configuration Options

Apply `#[disponent::configure(...)]` to the enum with any combination of:

- `inherent`: Generate inherent methods on the enum (vs trait impl)
- `inline`: Add `#[inline]` to all generated methods
- `from`: Generate `From` impls for each variant
- `try_into`: Generate `TryInto` impls for each variant

### Remote Traits

Use `#[disponent::remote(path::to::Trait)]` on the trait to forward to a trait defined elsewhere:

```rust
use external_crate::ExternalTrait;

declare!(
    pub enum MyEnum {
        Foo(Foo),
        Bar(Bar),
    }

    #[disponent::remote(ExternalTrait)]
    trait LocalTraitMirror {
        fn method(&self);
    }
);
```

## Generated Code

The above example generates the following code:

```rust
#[automatically_derived]
impl SayHello for FooOrBar {
    async fn say_hello(&self) -> () {
        match self {
            FooOrBar::Foo(inner) => SayHello::say_hello(inner).await,
            FooOrBar::Bar(inner) => SayHello::say_hello(inner).await,
        }
    }
    fn name(&self) -> &'static str {
        match self {
            FooOrBar::Foo(inner) => SayHello::name(inner),
            FooOrBar::Bar(inner) => SayHello::name(inner),
        }
    }
    fn with_default(&self) -> &'static str {
        match self {
            FooOrBar::Foo(inner) => SayHello::with_default(inner),
            FooOrBar::Bar(inner) => SayHello::with_default(inner),
        }
    }
}
```

In many cases, this can be substantially faster than using `dyn Trait` trait objects, especially when the enum is small and the methods are simple. See [the benchmarks of `enum_dispatch`](https://docs.rs/enum_dispatch/latest/enum_dispatch/#performance) for more details (benchmarks for `disponent` are coming soon).

## See also

- [**`ambassador`**]https://crates.io/crates/ambassador
- [**`declarative_enum_dispatch`**]https://crates.io/crates/declarative_enum_dispatch
- [**`delegate`**]https://crates.io/crates/delegate
- [**`delegation`**]https://crates.io/crates/delegation
- [**`enum_delegate`**]https://crates.io/crates/enum_delegate
- [**`enum_dispatch`**]https://crates.io/crates/enum_dispatch
- [**`polymorphic_enum`**]https://crates.io/crates/polymorphic_enum
- [**`spire_enum`**]https://crates.io/crates/spire_enum

With the exception of `declarative_enum_dispatch`, these crates all share state between macro invocations, which can lead to issues with `rust-analyzer` and similar tools. `disponent` avoids this by generating all code in a single macro invocation, at the cost of some flexibility in how the traits are defined (all while `rust-fmt` and error reporting works like normal).

## License

Licensed under either of [Apache License, Version 2.0](./LICENSE-APACHE) or [MIT license](./LICENSE-MIT) at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in disponent by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.