Skip to content

Commit

Permalink
Polish up docs
Browse files Browse the repository at this point in the history
  • Loading branch information
dynaxis committed Apr 17, 2020
1 parent 745e750 commit b02ed86
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 21 deletions.
34 changes: 24 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
# InterTrait
# Intertrait

![Build Status](https://github.com/CodeChain-io/intertrait/workflows/ci/badge.svg)
[![Latest Version](https://img.shields.io/crates/v/intertrait.svg)](https://crates.io/crates/intertrait)
[![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/intertrait)

This library provides direct casting among trait objects implemented by a type.

In Rust, an object of a sub-trait of [`std::any::Any`] can be downcast to a concrete type at runtime if the type is known. But no direct casting between two trait objects (i.e. without involving the concrete type of the backing value) are possible (even no coercion from a trait object to that of its super-trait yet).
In Rust, a trait object for a sub-trait of [`std::any::Any`] can be downcast to a concrete type at runtime
if the type is known. But no direct casting between two trait objects (i.e. without involving the concrete type
of the backing value) are possible (even no coercion from a trait object for a trait to that for its super-trait yet).

With this crate, any trait object with [`CastFrom`] as its super-trait can be cast directly to another trait object implemented by the underlying type if the target traits are registered beforehand with the macros provided by this crate.
With this crate, any trait object for a sub-trait of [`CastFrom`] can be cast directly to a trait object
for another trait implemented by the underlying type if the target traits are registered beforehand
with the macros provided by this crate.

# Usage
```rust
Expand Down Expand Up @@ -39,7 +43,7 @@ fn main() {
}
```

Target traits must be explicitly designated beforehand. There are three ways to do it:
Target traits must be explicitly designated beforehand. There are three ways of doing it:

## `#[cast_to]` to `impl` item
The trait implemented is designated as a target trait.
Expand Down Expand Up @@ -92,18 +96,28 @@ fn main() {}
```

# How it works
First of all, [`CastFrom`] trait makes it possible to retrieve an object of [`std::any::Any`] from an object of a sub-trait of [`CastFrom`].
First of all, [`CastFrom`] trait makes it possible to retrieve an object of [`std::any::Any`]
from an object for a sub-trait of [`CastFrom`].

> [`CastFrom`] will become obsolete and be replaced with [`std::any::Any`] once the [unsized coercion](https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions) from a trait object to an object of its super-trait is implemented in the stable Rust.
> [`CastFrom`] will become obsolete and be replaced with [`std::any::Any`]
> once [unsized coercion](https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions)
> from a trait object to another trait object for its super-trait is implemented in the stable Rust.
And the macros provided by `intertrait` generates trampoline functions for downcasting a trait object of [`std::any::Any`] back to its concrete type and then creating the target trait object from it.
And the macros provided by `intertrait` generates trampoline functions for downcasting a trait object
for [`std::any::Any`] back to its concrete type and then creating a trait object for the target trait from it.

Those trampoline functions are aggregated into a global registry using [`linkme`](https://github.com/dtolnay/linkme/) crate, which involves no (generally discouraged) life-before-main trick. The registry is keyed with a pair of [`TypeId`]s, which are for the concrete type backing an object of a sub-trait of [`CastFrom`] and the target trait (the actual implementation is a bit different here, but conceptually so).
Those trampoline functions are aggregated into a global registry
using [`linkme`](https://github.com/dtolnay/linkme/) crate, which involves no (generally discouraged)
life-before-main trick. The registry is keyed with a pair of [`TypeId`]s, which are those of the concrete type
backing a trait object for a sub-trait of [`CastFrom`] and the target trait (the actual implementation
is a bit different here, but conceptually so).

In the course, it doesn't rely on any unstable Rust implementation details such as the layout of trait objects that may be changed in the future.
In the course, it doesn't rely on any unstable Rust implementation details such as the layout of trait objects
that may be changed in the future.

# Credits
`intertrait` has taken much of its core ideas from the great [`traitcast`](https://github.com/bch29/traitcast) crate. This crate enhances mainly in the ergonomics.
`intertrait` has taken much of its core ideas from the great [`traitcast`](https://github.com/bch29/traitcast) crate.
This crate enhances mainly in the ergonomics.

# License
Licensed under either of
Expand Down
4 changes: 2 additions & 2 deletions macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ mod item_type;
/// fn greet(&self);
/// }
///
/// // Greet can be cast into from any CastFrom sub-trait object backed by Data.
/// // Greet can be cast into from any sub-trait of CastFrom implemented by Data.
/// #[cast_to]
/// impl Greet for Data {
/// fn greet(&self) {
Expand All @@ -42,7 +42,7 @@ mod item_type;
/// ## On a type definition
/// Use when a target trait is derived or implemented in an external crate.
/// ```
/// // Debug can be cast into from any CastFrom sub-trait object backed by Data.
/// // Debug can be cast into from any sub-trait of CastFrom implemented by Data
/// #[cast_to(std::fmt::Debug)]
/// #[derive(std::fmt::Debug)]
/// struct Data;
Expand Down
18 changes: 9 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,24 +96,24 @@ static CASTER_MAP: Lazy<HashMap<(TypeId, TypeId), BoxedCaster, BuildFastHasher>>
.collect()
});

/// A `Caster` knows how to cast a reference to or `Box` of a trait object of type `Any`
/// to a trait object of type `T`. Each `Caster` instance is specific to a concrete type.
/// A `Caster` knows how to cast a reference to or `Box` of a trait object for `Any`
/// to a trait object of trait `T`. Each `Caster` instance is specific to a concrete type.
/// That is, it knows how to cast to single specific trait implemented by single specific type.
///
/// An implementation of a trait for a concrete type doesn't need to manually provide
/// a `Caster`. Instead attach `#[cast_to]` to the `impl` block.
#[doc(hidden)]
pub struct Caster<T: ?Sized + 'static> {
/// Casts a reference to a trait object of type `Any` from a concrete type `S`
/// to a reference to a trait object of type `T`.
/// Casts a reference to a trait object for `Any` from a concrete type `S`
/// to a reference to a trait object for trait `T`.
pub cast_ref: fn(from: &dyn Any) -> Option<&T>,

/// Casts a mutable reference to a trait object of type `Any` from a concrete type `S`
/// to a mutable reference to a trait object of type `T`.
/// Casts a mutable reference to a trait object for `Any` from a concrete type `S`
/// to a mutable reference to a trait object for trait `T`.
pub cast_mut: fn(from: &mut dyn Any) -> Option<&mut T>,

/// Casts a `Box` holding a trait object of type `Any` from a concrete type `S`
/// to another `Box` holding a trait object of type `T`.
/// Casts a `Box` holding a trait object for `Any` from a concrete type `S`
/// to another `Box` holding a trait object for trait `T`.
pub cast_box: fn(from: Box<dyn Any>) -> CastBoxResult<T>,
}

Expand All @@ -138,7 +138,7 @@ fn caster<T: ?Sized + 'static>(type_id: TypeId) -> Option<&'static Caster<T>> {
///
/// **Note**: [`CastFrom`] will become obsolete and be replaced with [`std::any::Any`]
/// once the [unsized coercion](https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions)
/// from a trait object to an object of its super-trait is implemented in the stable Rust.
/// from a trait object to another for its super-trait is implemented in the stable Rust.
///
/// [`Any`]: https://doc.rust-lang.org/std/any/trait.Any.html
pub trait CastFrom {
Expand Down

0 comments on commit b02ed86

Please sign in to comment.