Skip to content

Commit

Permalink
Update docs for the API changes so far
Browse files Browse the repository at this point in the history
  • Loading branch information
dynaxis committed Apr 24, 2020
1 parent 4ea8c15 commit 9149155
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 11 deletions.
25 changes: 17 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ fn main() {

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

## `#[cast_to]` to `impl` item
### `#[cast_to]` to `impl` item
The trait implemented is designated as a target trait.

```rust
Expand All @@ -63,7 +63,7 @@ impl Greet for Data {
}
```

## `#[cast_to(Trait)]` to type definition
### `#[cast_to(Trait)]` to type definition
For the type, the traits specified as arguments to the `#[cast_to(...)]` attribute are designated as target traits.

```rust
Expand All @@ -82,7 +82,7 @@ impl Greet for Data {
struct Data;
```

## `castable_to!(Type => Trait1, Trait2)`
### `castable_to!(Type => Trait1, Trait2)`
For the type, the traits following `:` are designated as target traits.

```rust
Expand All @@ -103,14 +103,22 @@ castable_to!(Data => Greet, std::fmt::Debug);
fn main() {}
```

## `Arc` Support
`std::sync::Arc` is unique in that it implement `downcast` method only on `dyn Any + Send + Sync + 'static'.
To use with `Arc`, the following steps should be taken:

* Mark source traits with [`CastFromSync`] instead of [`CastFrom`]
* Add `[sync]` flag to `#[cast_to]` and `castable_to!` as follows:
```ignore
#[cast_to([sync])]
#[cast_to([sync] Trait1, Trait2)]
castable_to!(Type => [sync] Trait, Trait2);
```

# How it works
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 [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
for [`std::any::Any`] back to its concrete type and then creating a trait object for the target trait from it.

Expand Down Expand Up @@ -143,4 +151,5 @@ dual licensed as above, without any additional terms or conditions.

[`std::any::Any`]: https://doc.rust-lang.org/std/any/trait.Any.html
[`TypeId`]: https://doc.rust-lang.org/std/any/struct.TypeId.html
[`CastFrom`]: https://docs.rs/intertrait/*/intertrait/trait.CastFrom.html
[`CastFrom`]: https://docs.rs/intertrait/*/intertrait/trait.CastFrom.html
[`CastFromSync`]: https://docs.rs/intertrait/*/intertrait/trait.CastFromSync.html
31 changes: 30 additions & 1 deletion macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ mod item_type;
/// If on an `impl` item, no argument is allowed. But on a type definition, the target traits
/// must be listed explicitly.
///
/// Add `[sync]` before the list of traits if the underlying type is `Sync + Send` and you
/// need `std::sync::Arc`.
///
/// # Examples
/// ## On a trait impl
/// ```
Expand All @@ -43,6 +46,15 @@ mod item_type;
/// #[derive(std::fmt::Debug)]
/// struct Data;
/// ```
///
/// ## For Arc
/// Use when the underlying type is `Sync + Send` and you want to use `Arc`.
/// ```
/// // Debug can be cast into from any sub-trait of CastFrom implemented by Data
/// #[cast_to([sync] std::fmt::Debug)]
/// #[derive(std::fmt::Debug)]
/// struct Data;
/// ```
#[proc_macro_attribute]
pub fn cast_to(args: TokenStream, input: TokenStream) -> TokenStream {
match parse::<Targets>(args) {
Expand All @@ -60,7 +72,7 @@ pub fn cast_to(args: TokenStream, input: TokenStream) -> TokenStream {
.into()
}

/// Declare target traits for casting implemented by a type.
/// Declares target traits for casting implemented by a type.
///
/// This macro is for registering both a concrete type and its traits to be targets for casting.
/// Useful when the type definition and the trait implementations are in an external crate.
Expand All @@ -84,6 +96,23 @@ pub fn cast_to(args: TokenStream, input: TokenStream) -> TokenStream {
/// }
/// castable_to! { Data => std::fmt::Debug, Greet }
/// ```
///
/// When the type is `Sync + Send` and is used with `Arc`:
/// ```
/// #[derive(std::fmt::Debug)]
/// enum Data {
/// A, B, C
/// }
/// trait Greet {
/// fn greet(&self);
/// }
/// impl Greet for Data {
/// fn greet(&self) {
/// println!("Hello");
/// }
/// }
/// castable_to! { Data => [sync] std::fmt::Debug, Greet }
/// ```
#[proc_macro]
pub fn castable_to(input: TokenStream) -> TokenStream {
let Casts {
Expand Down
10 changes: 10 additions & 0 deletions src/cast.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
//! `cast` module contains traits to provide `cast` method for various references
//! and smart pointers.
//!
//! In source files requiring casts, import all of the traits as follows:
//!
//! ```ignore
//! use intertrait::cast::*;
//! ```
//!
//! Since there exists single trait for each receiver type, the same `cast` method is overloaded.
mod cast_arc;
mod cast_box;
mod cast_mut;
Expand Down
9 changes: 7 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! A library providing 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
//! In Rust, an object of a sub-trait of [`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).
Expand Down Expand Up @@ -45,14 +45,19 @@
//! * [`#[cast_to(Trait)]`][cast_to] to type definition
//! * [`castable_to!(Type => Trait1, Trait2)`][castable_to]
//!
//! Refer to the documents for each of macros for details.
//! If the underlying type involved is `Sync + Send` and you want to use it with [`Arc`],
//! use [`CastFromSync`] in place of [`CastFrom`] and add `[sync]` flag before the list
//! of traits in the macros. Refer to the documents for each of macros for details.
//!
//! For casting, refer to traits defined in [`cast`] module.
//!
//! [cast_to]: ./attr.cast_to.html
//! [castable_to]: ./macro.castable_to.html
//! [`CastFrom`]: ./trait.CastFrom.html
//! [`CastFromSync`]: ./trait.CastFromSync.html
//! [`cast`]: ./cast/index.html
//! [`Any`]: https://doc.rust-lang.org/std/any/trait.Any.html
//! [`Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html
use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::rc::Rc;
Expand Down

0 comments on commit 9149155

Please sign in to comment.