xref: /DragonOS/kernel/crates/intertrait/README.md (revision f5b2038871d3441e1c7f32439ff422957e7ab828)
1# Intertrait
2
3We forked this lib from [intertrait](https://github.com/CodeChain-io/intertrait/) (revision d5d6dcb), and modified it to support `no_std` environment.
4
5## Notice
6
7The modified version is licensed under GPLv2 and later, while the original version is licensed under MIT/Apache license.(Codes modified by us are licensed under GPLv2 and later.)
8
9
10This library provides direct casting among trait objects implemented by a type.
11
12In Rust, a trait object for a sub-trait of [`std::any::Any`] can be downcast to a concrete type at runtime
13if the type is known. But no direct casting between two trait objects (i.e. without involving the concrete type
14of the backing value) is possible (even no coercion from a trait object for a trait to that for its super-trait yet).
15
16With this crate, any trait object for a sub-trait of [`CastFrom`] can be cast directly to a trait object
17for another trait implemented by the underlying type if the target traits are registered beforehand
18with the macros provided by this crate.
19
20# Dependencies
21Add the following two dependencies to your `Cargo.toml`:
22
23```toml
24[dependencies]
25intertrait = "0.2"
26linkme = "=0.3.27"
27```
28
29The `linkme` dependency is required due to the use of `linkme` macro in the output of `intertrait` macros.
30
31# Usage
32
33```rust
34use intertrait::*;
35use intertrait::cast::*;
36
37struct Data;
38
39trait Source: CastFrom {}
40
41trait Greet {
42    fn greet(&self);
43}
44
45#[cast_to]
46impl Greet for Data {
47    fn greet(&self) {
48        println!("Hello");
49    }
50}
51
52impl Source for Data {}
53
54fn main() {
55    let data = Data;
56    let source: &dyn Source = &data;
57    let greet = source.cast::<dyn Greet>();
58    greet.unwrap().greet();
59}
60```
61
62Target traits must be explicitly designated beforehand. There are three ways of doing it:
63
64### `#[cast_to]` to `impl` item
65The trait implemented is designated as a target trait.
66
67```rust
68use intertrait::*;
69
70struct Data;
71trait Greet { fn greet(&self); }
72
73#[cast_to]
74impl Greet for Data {
75    fn greet(&self) {
76        println!("Hello");
77    }
78}
79```
80
81### `#[cast_to(Trait)]` to type definition
82For the type, the traits specified as arguments to the `#[cast_to(...)]` attribute are designated as target traits.
83
84```rust
85use intertrait::*;
86
87trait Greet { fn greet(&self); }
88
89impl Greet for Data {
90    fn greet(&self) {
91        println!("Hello");
92    }
93}
94
95#[cast_to(Greet, std::fmt::Debug)]
96#[derive(std::fmt::Debug)]
97struct Data;
98```
99
100### `castable_to!(Type => Trait1, Trait2)`
101For the type, the traits following `:` are designated as target traits.
102
103```rust
104use intertrait::*;
105
106#[derive(std::fmt::Debug)]
107struct Data;
108trait Greet { fn greet(&self); }
109impl Greet for Data {
110    fn greet(&self) {
111        println!("Hello");
112    }
113}
114// Only in an item position due to the current limitation in the stable Rust.
115// https://github.com/rust-lang/rust/pull/68717
116castable_to!(Data => Greet, std::fmt::Debug);
117
118fn main() {}
119```
120
121## `Arc` Support
122`std::sync::Arc` is unique in that it implements `downcast` method only on `dyn Any + Send + Sync + 'static'.
123To use with `Arc`, the following steps should be taken:
124
125* Mark source traits with [`CastFromSync`] instead of [`CastFrom`]
126* Add `[sync]` flag to `#[cast_to]` and `castable_to!` as follows:
127  ```ignore
128  #[cast_to([sync])]
129  #[cast_to([sync] Trait1, Trait2)]
130  castable_to!(Type => [sync] Trait, Trait2);
131  ```
132
133# How it works
134First of all, [`CastFrom`] trait makes it possible to retrieve an object of [`std::any::Any`]
135from an object for a sub-trait of [`CastFrom`].
136
137And the macros provided by `intertrait` generates trampoline functions for downcasting a trait object
138for [`std::any::Any`] back to its concrete type and then creating a trait object for the target trait from it.
139
140Those trampoline functions are aggregated into a global registry
141using [`linkme`](https://github.com/dtolnay/linkme/) crate, which involves no (generally discouraged)
142life-before-main trick. The registry is keyed with a pair of [`TypeId`]s, which are those of the concrete type
143backing a trait object for a sub-trait of [`CastFrom`] and the target trait (the actual implementation
144is a bit different here, but conceptually so).
145
146In the course, it doesn't rely on any unstable Rust implementation details such as the layout of trait objects
147that may be changed in the future.
148
149# Credits
150`intertrait` has taken much of its core ideas from the great [`traitcast`](https://github.com/bch29/traitcast) crate.
151
152# License
153The modified version is licensed under GPLv2 and later, while the original version is licensed under MIT/Apache license.(Codes modified by us are licensed under GPLv2 and later.)
154
155Modified version(revision 0.2.0):
156 * GPLv2 and later (You can find the full text of the license in the root directory of this repository.)
157
158Original version(revision d5d6dcb):
159 * Apache License, Version 2.0
160   ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
161 * MIT license
162   ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
163
164