trait_cast_rs 0.2.4

Get your own Any with support for casting to trait objects.
Documentation
#![no_std]
#![deny(missing_docs)]
#![warn(clippy::undocumented_unsafe_blocks, clippy::pedantic, clippy::nursery)]
#![allow(clippy::doc_markdown, clippy::option_if_let_else)]
#![allow(incomplete_features)]
#![feature(
  const_type_id,      // Needed to enable `TraitcastTarget::create` to be const
  const_type_name,    // Needed for `Debug` implementation
  trait_upcasting,    // Needed to avoid reimplementing Any
  const_mut_refs,     // Needed since arguments to `TraitcastTarget::create` need a function pointer with &mut argument and return type.
  min_specialization, // Needed to unify the interface between downcast and traitcast (could be avoided with !Trait bounds or trait generics)
  doc_cfg             // For nicer Docs
)]
#![cfg_attr(feature = "downcast_unchecked", feature(downcast_unchecked))]
#![cfg_attr(feature = "const_sort", feature(const_cmp, const_trait_impl))] // FIXME: Replace `const_cmp` with `const_cmp_type_id` once it lands

/*!
## Requirements

This crate requires a nightly compiler.

## What can this crate do?

This crate adds the `TraitcastableAny` replacement trait for `Any`.
It closely resembles the `Any` trait for downcasting to a concrete type.
Additionally the `TraitcastableAny` trait allows you to **directly** downcast to other `&dyn Trait`s.

To make this work you must specify all *target* traits you want to be able to downcast to in the `make_trait_castable(Trait1, Trait2, ...)` attribute macro.
This macro can be applied to structs, enums and unions.
It implements the `TraitcastableAny` trait for your struct, enum or union.

Note: No modifications on the *target* traits are necessary. Which allows you to downcast to traits of other libraries you don't control.

## Usage

1. Add the `trait_cast_rs` crate to your `Cargo.toml` and switch to a nightly compiler.

2. Add the `#[make_trait_castable(Trait1, Trait2, ...)]` macro to your struct/enum/union.
    List all traits you eventually want to be able to `downcast` to.
    You must implement all listed traits.

3. Use references to `dyn TraitcastableAny` throughout your code instead of `dyn Any`.

4. Enjoy downcasting to trait objects.

## Example

```rust
# #![cfg_attr(feature = "min_specialization", feature(min_specialization))]
# #![cfg_attr(feature = "const_sort", feature(const_trait_impl, const_mut_refs))]
use trait_cast_rs::{
  make_trait_castable, TraitcastableAny, TraitcastableAnyInfra, TraitcastableAnyInfraExt,
};
#[make_trait_castable(Print)]
struct Source(i32);
trait Print {
  fn print(&self);
}
impl Print for Source {
  fn print(&self) {
    println!("{}", self.0)
  }
}

let source = Box::new(Source(5));
let castable: Box<dyn TraitcastableAny> = source;
let x: &dyn Print = castable.downcast_ref().unwrap();
x.print();
```

## EVEN MORE Examples 🔥

Check out the [examples](https://github.com/ink-feather-org/trait_cast_rs/tree/main/trait_cast_rs/examples).

If you want to do something the `make_trait_castable` attribute macro can't handle (like implementing for generic structs - pull requests are welcome)
check out the `manual*.rs` examples.

There is also a decl marco available - check out the `with_decl_macro*.rs` examples.

## Features

* `alloc` - Adds special implementations for `Box`, `Rc` and `Arc`. Default feature.
* `const_sort` -
  Makes the `make_trait_castable` and `make_trait_castable_decl` macros sort the `traitcast_targets` at **compile_time**.
  When downcasting a `binary_search` is performed. **May** be 🚀 <span style="color: orange; font-weight: bolder">BLAZINGLY</span> 🚀 *faster* for types with **lots** of downcast targets.

  It additionally requires the following feature flags in the user code:
  `#![feature(const_trait_impl, const_mut_refs)]`
* `min_specialization` -
  Implements `TraitcastableAny` for `'static` types.
  Even types you don't control.
  However these default implementations of `TraitcastableAny` have no downcast targets.

  It additionally requires the following feature flags in the user code:
  `#![feature(min_specialization)]`
* `downcast_unchecked` - Adds `*_unchecked` variants to the downcast functions.

## Upcasting to the real `Any`

With the `trait_upcasting` rust feature you can even cast any `&dyn TraitcastableAny` to `&dyn Any`.
Alternatively you can list the `Any` trait as a traitcast target.
However it is not possible to cast back to `TraitcastableAny` (pull requests are welcome).

## Authors

[raldone01](https://github.com/raldone01) and [onestacked](https://github.com/chriss0612) are the primary authors and maintainers of this library.

## License

This project is released under either:

- [MIT License](https://github.com/ink-feather-org/trait_cast_rs/blob/main/LICENSE-MIT)
- [Apache License (Version 2.0)](https://github.com/ink-feather-org/trait_cast_rs/blob/main/LICENSE-APACHE)

at your choosing.

### Contribution

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

## How it works

I will give you a quick rundown of our *internal* operations: 💦

Compile time:

1. Add a `casting` function for every downcast path to the concrete type.
    This function gets a `dyn TraitcastableAny`, which it then downcasts to a concrete type using `Any` in the background.
    In the last step it casts the concrete type to the wanted trait object and returns it.

2. Add a `traitcast_targets` function that returns a const slice of (`typeid`, transmuted *casting* function ptr).

Runtime:

1. Get targets array
2. Find the target `typeid`
3. Transmute function pointer back to original type
4. Call the function pointer to get the wanted trait object
5. Return it
6. 💲 Profit 💲

## SAFETY 🏰

* The unchecked variants of the `downcast` function all use unsafe - expectedly.
* The only other use of unsafe is the transmutation of function pointers.
  However when they are called they are transmuted back to their original type.
  So this should be `105%` save. ~~As long as `TypeId`s don't collide.~~

## Alternatives (~~and why our crate is the best~~)

This alternatives section is not exhaustive for a more objective/detailed comparison
see the alternatives section of [cast_trait_object](https://crates.io/crates/cast_trait_object#Alternatives).

* [mopa](https://crates.io/crates/mopa):
    Had its last update 6 years ago.
    Has some unresolved [unsoundness issues](https://github.com/chris-morgan/mopa/issues/13).
    Also requires modifications on traits themselves while we just modify the struct/enum/union (see note above).
* [mopa-maintained](https://crates.io/crates/mopa-maintained):
    Might have fixed some issues but still has an old code base with just a version bump.
* [traitcast](https://crates.io/crates/traitcast):
    Has no readme on [crates.io](https://crates.io/).
    Uses a GLOBAL REGISTRY with `lazy_static`.
    To be fair it allows you to use the default `Any` and doesn't require nightly.

TODO: Remove this section once our last update is 6 years old.

### Links

[`std::any`](https://doc.rust-lang.org/nightly/std/any)

[`std::any::Any`](https://doc.rust-lang.org/nightly/std/any/trait.Any.html)

[`TypeId`](https://doc.rust-lang.org/nightly/std/any/struct.TypeId.html)

[`downcast-rs`](https://crates.io/crates/downcast-rs)

[`intertrait`](https://crates.io/crates/intertrait)

[`traitcast`](https://crates.io/crates/traitcast)

[`traitcast_core`](https://crates.io/crates/traitcast_core)

[`cast_trait_object`](https://crates.io/crates/cast_trait_object)

[`mopa`](https://crates.io/crates/mopa)

[`mopa-maintained`](https://crates.io/crates/mopa-maintained)

*/

#[cfg(feature = "alloc")]
extern crate alloc;

mod trait_cast;
pub use trait_cast::*;

mod decl_macro;

#[cfg(feature = "const_sort")]
#[doc(hidden)]
pub use const_sort_rs::ConstSliceSortExt;

pub use trait_cast_impl_rs::make_trait_castable;

#[cfg(test)]
mod test;