mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 18:26:48 +00:00
引入intertrait库,支持trait之间的互相转换 (#395)
* 能过编译(test还没法跑) * 初始化intertrait转换库 * update license of intertrait
This commit is contained in:
parent
bb0e4d4131
commit
fba5623183
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -181,5 +181,5 @@
|
|||||||
"rust-analyzer.checkOnSave.allTargets": false,
|
"rust-analyzer.checkOnSave.allTargets": false,
|
||||||
"rust-analyzer.linkedProjects": [
|
"rust-analyzer.linkedProjects": [
|
||||||
"./kernel/Cargo.toml"
|
"./kernel/Cargo.toml"
|
||||||
]
|
],
|
||||||
}
|
}
|
@ -5,9 +5,13 @@ edition = "2021"
|
|||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = ["staticlib"]
|
crate-type = ["staticlib"]
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
members = [ "src/libs/intertrait" ]
|
||||||
|
|
||||||
# 运行时依赖项
|
# 运行时依赖项
|
||||||
[dependencies]
|
[dependencies]
|
||||||
x86 = "0.52.0"
|
x86 = "0.52.0"
|
||||||
@ -28,6 +32,8 @@ memoffset = "0.9.0"
|
|||||||
atomic_enum = "0.2.0"
|
atomic_enum = "0.2.0"
|
||||||
raw-cpuid = "11.0.1"
|
raw-cpuid = "11.0.1"
|
||||||
acpi = "5.0.0"
|
acpi = "5.0.0"
|
||||||
|
intertrait = { path = "src/libs/intertrait" }
|
||||||
|
linkme = "0.2"
|
||||||
|
|
||||||
# 构建时依赖项
|
# 构建时依赖项
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
6
kernel/src/init/c_adapter.rs
Normal file
6
kernel/src/init/c_adapter.rs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
use super::init_intertrait;
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
unsafe extern "C" fn rs_init_intertrait() {
|
||||||
|
init_intertrait();
|
||||||
|
}
|
5
kernel/src/init/mod.rs
Normal file
5
kernel/src/init/mod.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
pub mod c_adapter;
|
||||||
|
|
||||||
|
fn init_intertrait() {
|
||||||
|
intertrait::init_caster_map();
|
||||||
|
}
|
@ -1,4 +1,3 @@
|
|||||||
#![no_std] // <1>
|
|
||||||
#![no_main] // <1>
|
#![no_main] // <1>
|
||||||
#![feature(alloc_error_handler)]
|
#![feature(alloc_error_handler)]
|
||||||
#![feature(allocator_api)]
|
#![feature(allocator_api)]
|
||||||
@ -15,6 +14,11 @@
|
|||||||
#![feature(trait_upcasting)]
|
#![feature(trait_upcasting)]
|
||||||
#![feature(slice_ptr_get)]
|
#![feature(slice_ptr_get)]
|
||||||
#![feature(vec_into_raw_parts)]
|
#![feature(vec_into_raw_parts)]
|
||||||
|
#![cfg_attr(target_os = "none", no_std)]
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate std;
|
||||||
|
|
||||||
#[allow(non_upper_case_globals)]
|
#[allow(non_upper_case_globals)]
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
@ -31,6 +35,7 @@ mod include;
|
|||||||
mod driver; // 如果driver依赖了libs,应该在libs后面导出
|
mod driver; // 如果driver依赖了libs,应该在libs后面导出
|
||||||
mod exception;
|
mod exception;
|
||||||
mod filesystem;
|
mod filesystem;
|
||||||
|
mod init;
|
||||||
mod ipc;
|
mod ipc;
|
||||||
mod mm;
|
mod mm;
|
||||||
mod net;
|
mod net;
|
||||||
@ -53,6 +58,8 @@ extern crate num;
|
|||||||
extern crate num_derive;
|
extern crate num_derive;
|
||||||
extern crate smoltcp;
|
extern crate smoltcp;
|
||||||
extern crate thingbuf;
|
extern crate thingbuf;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate intertrait;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
extern crate x86;
|
extern crate x86;
|
||||||
|
|
||||||
@ -65,6 +72,7 @@ use crate::process::ProcessManager;
|
|||||||
pub static KERNEL_ALLOCATOR: KernelAllocator = KernelAllocator;
|
pub static KERNEL_ALLOCATOR: KernelAllocator = KernelAllocator;
|
||||||
|
|
||||||
/// 全局的panic处理函数
|
/// 全局的panic处理函数
|
||||||
|
#[cfg(target_os = "none")]
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn panic(info: &PanicInfo) -> ! {
|
pub fn panic(info: &PanicInfo) -> ! {
|
||||||
|
18
kernel/src/libs/intertrait/.gitignore
vendored
Normal file
18
kernel/src/libs/intertrait/.gitignore
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Cargo lock in subs
|
||||||
|
**/Cargo.lock
|
||||||
|
|
||||||
|
# Generated by Cargo
|
||||||
|
**/target/
|
||||||
|
|
||||||
|
**/*.rs.bk
|
||||||
|
**/*.iml
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
/db/
|
||||||
|
/snapshot/
|
||||||
|
/log/
|
||||||
|
/keys/
|
||||||
|
/test/log/
|
||||||
|
|
||||||
|
# macOS
|
||||||
|
.DS_store
|
27
kernel/src/libs/intertrait/Cargo.toml
Normal file
27
kernel/src/libs/intertrait/Cargo.toml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
[package]
|
||||||
|
name = "intertrait"
|
||||||
|
version = "0.2.2"
|
||||||
|
authors = ["CodeChain Team <hi@codechain.io>"]
|
||||||
|
license = "GPLv2(for code modified by dragonos) MIT OR Apache-2.0"
|
||||||
|
description = "Allow for inter-trait casting"
|
||||||
|
edition = "2018"
|
||||||
|
repository = "https://github.com/CodeChain-io/intertrait"
|
||||||
|
documentation = "https://docs.rs/intertrait"
|
||||||
|
readme = "README.md"
|
||||||
|
categories = ["rust-patterns"]
|
||||||
|
keywords = ["trait", "cast", "any"]
|
||||||
|
include = ["src/**/*", "Cargo.toml", "LICENSE-*", "README.md"]
|
||||||
|
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
linkme = "0.2"
|
||||||
|
hashbrown = "0.13.2"
|
||||||
|
intertrait-macros = { version = "=0.2.2", path = "macros" }
|
||||||
|
|
||||||
|
[target.'cfg(not(target_os = "none"))'.dependencies]
|
||||||
|
once_cell = "1.4"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
trybuild = "1.0"
|
||||||
|
doc-comment = "0.3"
|
||||||
|
|
17
kernel/src/libs/intertrait/LICENSE-MIT
Normal file
17
kernel/src/libs/intertrait/LICENSE-MIT
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
163
kernel/src/libs/intertrait/README.md
Normal file
163
kernel/src/libs/intertrait/README.md
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
# Intertrait
|
||||||
|
|
||||||
|
We forked this lib from [intertrait](https://github.com/CodeChain-io/intertrait/) (revision d5d6dcb), and modified it to support `no_std` environment.
|
||||||
|
|
||||||
|
## Notice
|
||||||
|
|
||||||
|
The 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.)
|
||||||
|
|
||||||
|
|
||||||
|
This library provides direct casting among trait objects implemented by a type.
|
||||||
|
|
||||||
|
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) is possible (even no coercion from a trait object for a trait to that for its super-trait yet).
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
# Dependencies
|
||||||
|
Add the following two dependencies to your `Cargo.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
intertrait = "0.2"
|
||||||
|
linkme = "0.2"
|
||||||
|
```
|
||||||
|
|
||||||
|
The `linkme` dependency is required due to the use of `linkme` macro in the output of `intertrait` macros.
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use intertrait::*;
|
||||||
|
use intertrait::cast::*;
|
||||||
|
|
||||||
|
struct Data;
|
||||||
|
|
||||||
|
trait Source: CastFrom {}
|
||||||
|
|
||||||
|
trait Greet {
|
||||||
|
fn greet(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cast_to]
|
||||||
|
impl Greet for Data {
|
||||||
|
fn greet(&self) {
|
||||||
|
println!("Hello");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Source for Data {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let data = Data;
|
||||||
|
let source: &dyn Source = &data;
|
||||||
|
let greet = source.cast::<dyn Greet>();
|
||||||
|
greet.unwrap().greet();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use intertrait::*;
|
||||||
|
|
||||||
|
struct Data;
|
||||||
|
trait Greet { fn greet(&self); }
|
||||||
|
|
||||||
|
#[cast_to]
|
||||||
|
impl Greet for Data {
|
||||||
|
fn greet(&self) {
|
||||||
|
println!("Hello");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `#[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
|
||||||
|
use intertrait::*;
|
||||||
|
|
||||||
|
trait Greet { fn greet(&self); }
|
||||||
|
|
||||||
|
impl Greet for Data {
|
||||||
|
fn greet(&self) {
|
||||||
|
println!("Hello");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cast_to(Greet, std::fmt::Debug)]
|
||||||
|
#[derive(std::fmt::Debug)]
|
||||||
|
struct Data;
|
||||||
|
```
|
||||||
|
|
||||||
|
### `castable_to!(Type => Trait1, Trait2)`
|
||||||
|
For the type, the traits following `:` are designated as target traits.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use intertrait::*;
|
||||||
|
|
||||||
|
#[derive(std::fmt::Debug)]
|
||||||
|
struct Data;
|
||||||
|
trait Greet { fn greet(&self); }
|
||||||
|
impl Greet for Data {
|
||||||
|
fn greet(&self) {
|
||||||
|
println!("Hello");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Only in an item position due to the current limitation in the stable Rust.
|
||||||
|
// https://github.com/rust-lang/rust/pull/68717
|
||||||
|
castable_to!(Data => Greet, std::fmt::Debug);
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
|
```
|
||||||
|
|
||||||
|
## `Arc` Support
|
||||||
|
`std::sync::Arc` is unique in that it implements `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`].
|
||||||
|
|
||||||
|
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 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.
|
||||||
|
|
||||||
|
# Credits
|
||||||
|
`intertrait` has taken much of its core ideas from the great [`traitcast`](https://github.com/bch29/traitcast) crate.
|
||||||
|
|
||||||
|
# License
|
||||||
|
The 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.)
|
||||||
|
|
||||||
|
Modified version(revision 0.2.0):
|
||||||
|
* GPLv2 and later (You can find the full text of the license in the root directory of this repository.)
|
||||||
|
|
||||||
|
Original version(revision d5d6dcb):
|
||||||
|
* Apache License, Version 2.0
|
||||||
|
([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
* MIT license
|
||||||
|
([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||||
|
|
23
kernel/src/libs/intertrait/macros/Cargo.toml
Normal file
23
kernel/src/libs/intertrait/macros/Cargo.toml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
[package]
|
||||||
|
name = "intertrait-macros"
|
||||||
|
description = "Macros for intertrait crate, which allows for direct casting between trait objects"
|
||||||
|
version = "0.2.2"
|
||||||
|
authors = ["CodeChain Team <hi@codechain.io>"]
|
||||||
|
license = "GPLv2(for code modified by dragonos) MIT OR Apache-2.0"
|
||||||
|
edition = "2018"
|
||||||
|
repository = "https://github.com/CodeChain-io/intertrait"
|
||||||
|
include = ["src/**/*", "Cargo.toml", "LICENSE-*"]
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
proc-macro = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
hashbrown = "0.13.2"
|
||||||
|
proc-macro2 = "1.0"
|
||||||
|
syn = { version = "1.0", features = ["full"] }
|
||||||
|
quote = "1.0"
|
||||||
|
uuid = { version = "0.8", features = ["v4"] }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
intertrait = { version = "=0.2.2", path = ".." }
|
||||||
|
linkme = "0.2"
|
176
kernel/src/libs/intertrait/macros/LICENSE-APACHE
Normal file
176
kernel/src/libs/intertrait/macros/LICENSE-APACHE
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
17
kernel/src/libs/intertrait/macros/LICENSE-MIT
Normal file
17
kernel/src/libs/intertrait/macros/LICENSE-MIT
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
76
kernel/src/libs/intertrait/macros/src/args.rs
Normal file
76
kernel/src/libs/intertrait/macros/src/args.rs
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
use hashbrown::HashSet;
|
||||||
|
use syn::bracketed;
|
||||||
|
use syn::parse::{Parse, ParseStream, Result};
|
||||||
|
use syn::punctuated::Punctuated;
|
||||||
|
use syn::{Error, Ident, Path, Token, Type};
|
||||||
|
|
||||||
|
#[derive(Hash, PartialEq, Eq)]
|
||||||
|
pub enum Flag {
|
||||||
|
Sync,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Flag {
|
||||||
|
fn from(ident: &Ident) -> Result<Self> {
|
||||||
|
match ident.to_string().as_str() {
|
||||||
|
"sync" => Ok(Flag::Sync),
|
||||||
|
unknown => {
|
||||||
|
let msg = format!("Unknown flag: {}", unknown);
|
||||||
|
Err(Error::new_spanned(ident, msg))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Targets {
|
||||||
|
pub flags: HashSet<Flag>,
|
||||||
|
pub paths: Vec<Path>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for Targets {
|
||||||
|
fn parse(input: ParseStream) -> Result<Self> {
|
||||||
|
let mut flags = HashSet::new();
|
||||||
|
let mut paths = Vec::new();
|
||||||
|
|
||||||
|
if input.is_empty() {
|
||||||
|
return Ok(Targets { flags, paths });
|
||||||
|
}
|
||||||
|
|
||||||
|
if input.peek(syn::token::Bracket) {
|
||||||
|
let content;
|
||||||
|
bracketed!(content in input);
|
||||||
|
for ident in Punctuated::<Ident, Token![,]>::parse_terminated(&content)? {
|
||||||
|
if !flags.insert(Flag::from(&ident)?) {
|
||||||
|
let msg = format!("Duplicated flag: {}", ident);
|
||||||
|
return Err(Error::new_spanned(ident, msg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if input.is_empty() {
|
||||||
|
return Ok(Targets { flags, paths });
|
||||||
|
}
|
||||||
|
|
||||||
|
paths = Punctuated::<Path, Token![,]>::parse_terminated(input)?
|
||||||
|
.into_iter()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Ok(Targets { flags, paths })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Casts {
|
||||||
|
pub ty: Type,
|
||||||
|
pub targets: Targets,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for Casts {
|
||||||
|
fn parse(input: ParseStream) -> Result<Self> {
|
||||||
|
let ty: Type = input.parse()?;
|
||||||
|
input.parse::<Token![=>]>()?;
|
||||||
|
|
||||||
|
Ok(Casts {
|
||||||
|
ty,
|
||||||
|
targets: input.parse()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
64
kernel/src/libs/intertrait/macros/src/gen_caster.rs
Normal file
64
kernel/src/libs/intertrait/macros/src/gen_caster.rs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
use core::str::from_utf8_unchecked;
|
||||||
|
|
||||||
|
use proc_macro2::TokenStream;
|
||||||
|
use uuid::adapter::Simple;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use quote::format_ident;
|
||||||
|
use quote::quote;
|
||||||
|
use quote::ToTokens;
|
||||||
|
|
||||||
|
pub fn generate_caster(ty: &impl ToTokens, trait_: &impl ToTokens, sync: bool) -> TokenStream {
|
||||||
|
let mut fn_buf = [0u8; FN_BUF_LEN];
|
||||||
|
let fn_ident = format_ident!("{}", new_fn_name(&mut fn_buf));
|
||||||
|
// 生成从dyn trait转换为具体类型结构体ty的caster
|
||||||
|
let new_caster = if sync {
|
||||||
|
quote! {
|
||||||
|
::intertrait::Caster::<dyn #trait_>::new_sync(
|
||||||
|
|from| from.downcast_ref::<#ty>().unwrap(),
|
||||||
|
|from| from.downcast_mut::<#ty>().unwrap(),
|
||||||
|
|from| from.downcast::<#ty>().unwrap(),
|
||||||
|
|from| from.downcast::<#ty>().unwrap(),
|
||||||
|
|from| from.downcast::<#ty>().unwrap()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {
|
||||||
|
::intertrait::Caster::<dyn #trait_>::new(
|
||||||
|
|from| from.downcast_ref::<#ty>().unwrap(),
|
||||||
|
|from| from.downcast_mut::<#ty>().unwrap(),
|
||||||
|
|from| from.downcast::<#ty>().unwrap(),
|
||||||
|
|from| from.downcast::<#ty>().unwrap(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 由于过程宏是在预编译期执行的,这里的target_os是linux。
|
||||||
|
// 编译完成的proc macro会交给下一阶段进行编译,因此,#[cfg(target_os)]会在下一阶段生效。
|
||||||
|
// 我们必须在预处理阶段把两种代码的token stream都生成出来,然后在下一阶段选择性地使用其中一种。
|
||||||
|
quote! {
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "none"))]
|
||||||
|
#[::linkme::distributed_slice(::intertrait::CASTERS)]
|
||||||
|
fn #fn_ident() -> (::std::any::TypeId, ::intertrait::BoxedCaster) {
|
||||||
|
(::std::any::TypeId::of::<#ty>(), Box::new(#new_caster))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "none")]
|
||||||
|
#[::linkme::distributed_slice(::intertrait::CASTERS)]
|
||||||
|
fn #fn_ident() -> (::core::any::TypeId, ::intertrait::BoxedCaster) {
|
||||||
|
(::core::any::TypeId::of::<#ty>(), alloc::boxed::Box::new(#new_caster))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const FN_PREFIX: &[u8] = b"__";
|
||||||
|
const FN_BUF_LEN: usize = FN_PREFIX.len() + Simple::LENGTH;
|
||||||
|
|
||||||
|
fn new_fn_name(buf: &mut [u8]) -> &str {
|
||||||
|
buf[..FN_PREFIX.len()].copy_from_slice(FN_PREFIX);
|
||||||
|
Uuid::new_v4()
|
||||||
|
.to_simple()
|
||||||
|
.encode_lower(&mut buf[FN_PREFIX.len()..]);
|
||||||
|
unsafe { from_utf8_unchecked(&buf[..FN_BUF_LEN]) }
|
||||||
|
}
|
82
kernel/src/libs/intertrait/macros/src/item_impl.rs
Normal file
82
kernel/src/libs/intertrait/macros/src/item_impl.rs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
use hashbrown::HashSet;
|
||||||
|
use proc_macro2::TokenStream;
|
||||||
|
use quote::{quote, quote_spanned, ToTokens};
|
||||||
|
use syn::punctuated::Punctuated;
|
||||||
|
use syn::spanned::Spanned;
|
||||||
|
use syn::Token;
|
||||||
|
use syn::{
|
||||||
|
AngleBracketedGenericArguments, Binding, GenericArgument, ImplItem, ItemImpl, Path,
|
||||||
|
PathArguments,
|
||||||
|
};
|
||||||
|
use PathArguments::AngleBracketed;
|
||||||
|
|
||||||
|
use crate::args::Flag;
|
||||||
|
use crate::gen_caster::generate_caster;
|
||||||
|
|
||||||
|
pub fn process(flags: &HashSet<Flag>, input: ItemImpl) -> TokenStream {
|
||||||
|
let ItemImpl {
|
||||||
|
ref self_ty,
|
||||||
|
ref trait_,
|
||||||
|
ref items,
|
||||||
|
..
|
||||||
|
} = input;
|
||||||
|
|
||||||
|
let generated = match trait_ {
|
||||||
|
None => quote_spanned! {
|
||||||
|
self_ty.span() => compile_error!("#[cast_to] should only be on an impl of a trait");
|
||||||
|
},
|
||||||
|
Some(trait_) => match trait_ {
|
||||||
|
(Some(bang), _, _) => quote_spanned! {
|
||||||
|
bang.span() => compile_error!("#[cast_to] is not for !Trait impl");
|
||||||
|
},
|
||||||
|
(None, path, _) => {
|
||||||
|
let path = fully_bound_trait(path, items);
|
||||||
|
generate_caster(self_ty, &path, flags.contains(&Flag::Sync))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
#input
|
||||||
|
#generated
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fully_bound_trait(path: &Path, items: &[ImplItem]) -> impl ToTokens {
|
||||||
|
let bindings = items
|
||||||
|
.iter()
|
||||||
|
.filter_map(|item| {
|
||||||
|
if let ImplItem::Type(assoc_ty) = item {
|
||||||
|
Some(GenericArgument::Binding(Binding {
|
||||||
|
ident: assoc_ty.ident.to_owned(),
|
||||||
|
eq_token: Default::default(),
|
||||||
|
ty: assoc_ty.ty.to_owned(),
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Punctuated<_, Token![,]>>();
|
||||||
|
|
||||||
|
let mut path = path.clone();
|
||||||
|
|
||||||
|
if bindings.is_empty() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(last) = path.segments.last_mut() {
|
||||||
|
match &mut last.arguments {
|
||||||
|
PathArguments::None => {
|
||||||
|
last.arguments = AngleBracketed(AngleBracketedGenericArguments {
|
||||||
|
colon2_token: None,
|
||||||
|
lt_token: Default::default(),
|
||||||
|
args: bindings,
|
||||||
|
gt_token: Default::default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
AngleBracketed(args) => args.args.extend(bindings),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
path
|
||||||
|
}
|
31
kernel/src/libs/intertrait/macros/src/item_type.rs
Normal file
31
kernel/src/libs/intertrait/macros/src/item_type.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
use hashbrown::HashSet;
|
||||||
|
use proc_macro2::TokenStream;
|
||||||
|
use syn::spanned::Spanned;
|
||||||
|
use syn::{DeriveInput, Path};
|
||||||
|
|
||||||
|
use quote::{quote, quote_spanned};
|
||||||
|
|
||||||
|
use crate::args::Flag;
|
||||||
|
use crate::gen_caster::generate_caster;
|
||||||
|
|
||||||
|
pub fn process(flags: &HashSet<Flag>, paths: Vec<Path>, input: DeriveInput) -> TokenStream {
|
||||||
|
let DeriveInput {
|
||||||
|
ref ident,
|
||||||
|
ref generics,
|
||||||
|
..
|
||||||
|
} = input;
|
||||||
|
let generated = if generics.lt_token.is_some() {
|
||||||
|
quote_spanned! {
|
||||||
|
generics.span() => compile_error!("#[cast_to(..)] can't be used on a generic type definition");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
paths
|
||||||
|
.into_iter()
|
||||||
|
.flat_map(|t| generate_caster(ident, &t, flags.contains(&Flag::Sync)))
|
||||||
|
.collect()
|
||||||
|
};
|
||||||
|
quote! {
|
||||||
|
#input
|
||||||
|
#generated
|
||||||
|
}
|
||||||
|
}
|
145
kernel/src/libs/intertrait/macros/src/lib.rs
Normal file
145
kernel/src/libs/intertrait/macros/src/lib.rs
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
extern crate proc_macro;
|
||||||
|
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
|
||||||
|
use syn::{parse, parse_macro_input, DeriveInput, ItemImpl};
|
||||||
|
|
||||||
|
use args::{Casts, Flag, Targets};
|
||||||
|
use gen_caster::generate_caster;
|
||||||
|
|
||||||
|
mod args;
|
||||||
|
mod gen_caster;
|
||||||
|
mod item_impl;
|
||||||
|
mod item_type;
|
||||||
|
|
||||||
|
/// Attached on an `impl` item or type definition, registers traits as targets for casting.
|
||||||
|
///
|
||||||
|
/// 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
|
||||||
|
/// ```
|
||||||
|
/// use intertrait::*;
|
||||||
|
///
|
||||||
|
/// struct Data;
|
||||||
|
///
|
||||||
|
/// trait Greet {
|
||||||
|
/// fn greet(&self);
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// // Greet can be cast into from any sub-trait of CastFrom implemented by Data.
|
||||||
|
/// #[cast_to]
|
||||||
|
/// impl Greet for Data {
|
||||||
|
/// fn greet(&self) {
|
||||||
|
/// println!("Hello");
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ## On a type definition
|
||||||
|
/// Use when a target trait is derived or implemented in an external crate.
|
||||||
|
/// ```
|
||||||
|
/// use intertrait::*;
|
||||||
|
///
|
||||||
|
/// // 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;
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ## For Arc
|
||||||
|
/// Use when the underlying type is `Sync + Send` and you want to use `Arc`.
|
||||||
|
/// ```
|
||||||
|
/// use intertrait::*;
|
||||||
|
///
|
||||||
|
/// // 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) {
|
||||||
|
Ok(Targets { flags, paths }) => {
|
||||||
|
if paths.is_empty() {
|
||||||
|
item_impl::process(&flags, parse_macro_input!(input as ItemImpl))
|
||||||
|
} else {
|
||||||
|
item_type::process(&flags, paths, parse_macro_input!(input as DeriveInput))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => vec![err.to_compile_error(), input.into()]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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.
|
||||||
|
///
|
||||||
|
/// **Note**: this macro cannot be used in an expression or statement prior to Rust 1.45.0,
|
||||||
|
/// due to [a previous limitation](https://github.com/rust-lang/rust/pull/68717).
|
||||||
|
/// If you want to use it in an expression or statement, use Rust 1.45.0 or later.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ```
|
||||||
|
/// use intertrait::*;
|
||||||
|
///
|
||||||
|
/// #[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 => std::fmt::Debug, Greet }
|
||||||
|
///
|
||||||
|
/// # fn main() {}
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// When the type is `Sync + Send` and is used with `Arc`:
|
||||||
|
/// ```
|
||||||
|
/// use intertrait::*;
|
||||||
|
///
|
||||||
|
/// #[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 }
|
||||||
|
///
|
||||||
|
/// # fn main() {}
|
||||||
|
/// ```
|
||||||
|
#[proc_macro]
|
||||||
|
pub fn castable_to(input: TokenStream) -> TokenStream {
|
||||||
|
let Casts {
|
||||||
|
ty,
|
||||||
|
targets: Targets { flags, paths },
|
||||||
|
} = parse_macro_input!(input);
|
||||||
|
|
||||||
|
paths
|
||||||
|
.iter()
|
||||||
|
.map(|t| generate_caster(&ty, t, flags.contains(&Flag::Sync)))
|
||||||
|
.collect::<proc_macro2::TokenStream>()
|
||||||
|
.into()
|
||||||
|
}
|
21
kernel/src/libs/intertrait/src/cast.rs
Normal file
21
kernel/src/libs/intertrait/src/cast.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
//! `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;
|
||||||
|
mod cast_rc;
|
||||||
|
mod cast_ref;
|
||||||
|
|
||||||
|
pub use cast_arc::*;
|
||||||
|
pub use cast_box::*;
|
||||||
|
pub use cast_mut::*;
|
||||||
|
pub use cast_rc::*;
|
||||||
|
pub use cast_ref::*;
|
45
kernel/src/libs/intertrait/src/cast/cast_arc.rs
Normal file
45
kernel/src/libs/intertrait/src/cast/cast_arc.rs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
use alloc::sync::Arc;
|
||||||
|
|
||||||
|
use crate::{caster, CastFromSync};
|
||||||
|
|
||||||
|
/// A trait that is blanket-implemented for traits extending `CastFrom` to allow for casting
|
||||||
|
/// of a trait object for it behind an `Rc` to a trait object for another trait
|
||||||
|
/// implemented by the underlying value.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ```
|
||||||
|
/// # use std::sync::Arc;
|
||||||
|
/// # use intertrait::*;
|
||||||
|
/// use intertrait::cast::*;
|
||||||
|
///
|
||||||
|
/// # #[cast_to([sync] Greet)]
|
||||||
|
/// # struct Data;
|
||||||
|
/// # trait Source: CastFrom {}
|
||||||
|
/// # trait Greet {
|
||||||
|
/// # fn greet(&self);
|
||||||
|
/// # }
|
||||||
|
/// # impl Greet for Data {
|
||||||
|
/// # fn greet(&self) {
|
||||||
|
/// # println!("Hello");
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// impl Source for Data {}
|
||||||
|
/// let data = Data;
|
||||||
|
/// let source = Arc::new(data);
|
||||||
|
/// let greet = source.cast::<dyn Greet>();
|
||||||
|
/// greet.unwrap_or_else(|_| panic!("must not happen")).greet();
|
||||||
|
/// ```
|
||||||
|
pub trait CastArc {
|
||||||
|
/// Casts an `Arc` for this trait into that for type `T`.
|
||||||
|
fn cast<T: ?Sized + 'static>(self: Arc<Self>) -> Result<Arc<T>, Arc<Self>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A blanket implementation of `CastArc` for traits extending `CastFrom`, `Sync`, and `Send`.
|
||||||
|
impl<S: ?Sized + CastFromSync> CastArc for S {
|
||||||
|
fn cast<T: ?Sized + 'static>(self: Arc<Self>) -> Result<Arc<T>, Arc<Self>> {
|
||||||
|
match caster::<T>((*self).type_id()) {
|
||||||
|
Some(caster) => Ok((caster.cast_arc)(self.arc_any())),
|
||||||
|
None => Err(self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
44
kernel/src/libs/intertrait/src/cast/cast_box.rs
Normal file
44
kernel/src/libs/intertrait/src/cast/cast_box.rs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
use alloc::boxed::Box;
|
||||||
|
|
||||||
|
use crate::{caster, CastFrom};
|
||||||
|
|
||||||
|
/// A trait that is blanket-implemented for traits extending `CastFrom` to allow for casting
|
||||||
|
/// of a trait object for it behind a `Box` to a trait object for another trait
|
||||||
|
/// implemented by the underlying value.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ```
|
||||||
|
/// # use intertrait::*;
|
||||||
|
/// use intertrait::cast::*;
|
||||||
|
///
|
||||||
|
/// # #[cast_to(Greet)]
|
||||||
|
/// # struct Data;
|
||||||
|
/// # trait Source: CastFrom {}
|
||||||
|
/// # trait Greet {
|
||||||
|
/// # fn greet(&self);
|
||||||
|
/// # }
|
||||||
|
/// # impl Greet for Data {
|
||||||
|
/// # fn greet(&self) {
|
||||||
|
/// # println!("Hello");
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// impl Source for Data {}
|
||||||
|
/// let data = Box::new(Data);
|
||||||
|
/// let source: Box<dyn Source> = data;
|
||||||
|
/// let greet = source.cast::<dyn Greet>();
|
||||||
|
/// greet.unwrap_or_else(|_| panic!("casting failed")).greet();
|
||||||
|
/// ```
|
||||||
|
pub trait CastBox {
|
||||||
|
/// Casts a box to this trait into that of type `T`. If fails, returns the receiver.
|
||||||
|
fn cast<T: ?Sized + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Self>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A blanket implementation of `CastBox` for traits extending `CastFrom`.
|
||||||
|
impl<S: ?Sized + CastFrom> CastBox for S {
|
||||||
|
fn cast<T: ?Sized + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Self>> {
|
||||||
|
match caster::<T>((*self).type_id()) {
|
||||||
|
Some(caster) => Ok((caster.cast_box)(self.box_any())),
|
||||||
|
None => Err(self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
41
kernel/src/libs/intertrait/src/cast/cast_mut.rs
Normal file
41
kernel/src/libs/intertrait/src/cast/cast_mut.rs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
use crate::{caster, CastFrom};
|
||||||
|
|
||||||
|
/// A trait that is blanket-implemented for traits extending `CastFrom` to allow for casting
|
||||||
|
/// of a trait object for it behind an mutable reference to a trait object for another trait
|
||||||
|
/// implemented by the underlying value.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ```
|
||||||
|
/// # use intertrait::*;
|
||||||
|
/// use intertrait::cast::*;
|
||||||
|
///
|
||||||
|
/// # #[cast_to(Greet)]
|
||||||
|
/// # struct Data;
|
||||||
|
/// # trait Source: CastFrom {}
|
||||||
|
/// # trait Greet {
|
||||||
|
/// # fn greet(&self);
|
||||||
|
/// # }
|
||||||
|
/// # impl Greet for Data {
|
||||||
|
/// # fn greet(&self) {
|
||||||
|
/// # println!("Hello");
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// impl Source for Data {}
|
||||||
|
/// let mut data = Data;
|
||||||
|
/// let source: &mut dyn Source = &mut data;
|
||||||
|
/// let greet = source.cast::<dyn Greet>();
|
||||||
|
/// greet.unwrap().greet();
|
||||||
|
/// ```
|
||||||
|
pub trait CastMut {
|
||||||
|
/// Casts a mutable reference to this trait into that of type `T`.
|
||||||
|
fn cast<T: ?Sized + 'static>(&mut self) -> Option<&mut T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A blanket implementation of `CastMut` for traits extending `CastFrom`.
|
||||||
|
impl<S: ?Sized + CastFrom> CastMut for S {
|
||||||
|
fn cast<T: ?Sized + 'static>(&mut self) -> Option<&mut T> {
|
||||||
|
let any = self.mut_any();
|
||||||
|
let caster = caster::<T>((*any).type_id())?;
|
||||||
|
(caster.cast_mut)(any).into()
|
||||||
|
}
|
||||||
|
}
|
44
kernel/src/libs/intertrait/src/cast/cast_rc.rs
Normal file
44
kernel/src/libs/intertrait/src/cast/cast_rc.rs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
use crate::{caster, CastFrom};
|
||||||
|
use alloc::rc::Rc;
|
||||||
|
|
||||||
|
/// A trait that is blanket-implemented for traits extending `CastFrom` to allow for casting
|
||||||
|
/// of a trait object for it behind an `Rc` to a trait object for another trait
|
||||||
|
/// implemented by the underlying value.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ```
|
||||||
|
/// # use std::rc::Rc;
|
||||||
|
/// # use intertrait::*;
|
||||||
|
/// use intertrait::cast::*;
|
||||||
|
///
|
||||||
|
/// # #[cast_to(Greet)]
|
||||||
|
/// # struct Data;
|
||||||
|
/// # trait Source: CastFrom {}
|
||||||
|
/// # trait Greet {
|
||||||
|
/// # fn greet(&self);
|
||||||
|
/// # }
|
||||||
|
/// # impl Greet for Data {
|
||||||
|
/// # fn greet(&self) {
|
||||||
|
/// # println!("Hello");
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// impl Source for Data {}
|
||||||
|
/// let data = Data;
|
||||||
|
/// let source = Rc::new(data);
|
||||||
|
/// let greet = source.cast::<dyn Greet>();
|
||||||
|
/// greet.unwrap_or_else(|_| panic!("must not happen")).greet();
|
||||||
|
/// ```
|
||||||
|
pub trait CastRc {
|
||||||
|
/// Casts an `Rc` for this trait into that for type `T`.
|
||||||
|
fn cast<T: ?Sized + 'static>(self: Rc<Self>) -> Result<Rc<T>, Rc<Self>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A blanket implementation of `CastRc` for traits extending `CastFrom`.
|
||||||
|
impl<S: ?Sized + CastFrom> CastRc for S {
|
||||||
|
fn cast<T: ?Sized + 'static>(self: Rc<Self>) -> Result<Rc<T>, Rc<Self>> {
|
||||||
|
match caster::<T>((*self).type_id()) {
|
||||||
|
Some(caster) => Ok((caster.cast_rc)(self.rc_any())),
|
||||||
|
None => Err(self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
84
kernel/src/libs/intertrait/src/cast/cast_ref.rs
Normal file
84
kernel/src/libs/intertrait/src/cast/cast_ref.rs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
use core::any::TypeId;
|
||||||
|
|
||||||
|
use crate::{caster, CastFrom, Caster};
|
||||||
|
|
||||||
|
/// A trait that is blanket-implemented for traits extending `CastFrom` to allow for casting
|
||||||
|
/// of a trait object for it behind an immutable reference to a trait object for another trait
|
||||||
|
/// implemented by the underlying value.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ## Casting an immutable reference
|
||||||
|
/// ```
|
||||||
|
/// # use intertrait::*;
|
||||||
|
/// use intertrait::cast::*;
|
||||||
|
///
|
||||||
|
/// # #[cast_to(Greet)]
|
||||||
|
/// # struct Data;
|
||||||
|
/// # trait Source: CastFrom {}
|
||||||
|
/// # trait Greet {
|
||||||
|
/// # fn greet(&self);
|
||||||
|
/// # }
|
||||||
|
/// # impl Greet for Data {
|
||||||
|
/// # fn greet(&self) {
|
||||||
|
/// # println!("Hello");
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// impl Source for Data {}
|
||||||
|
/// let data = Data;
|
||||||
|
/// let source: &dyn Source = &data;
|
||||||
|
/// let greet = source.cast::<dyn Greet>();
|
||||||
|
/// greet.unwrap().greet();
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ## Testing if a cast is possible
|
||||||
|
/// ```
|
||||||
|
/// # use intertrait::*;
|
||||||
|
/// use intertrait::cast::*;
|
||||||
|
///
|
||||||
|
/// # #[cast_to(Greet)]
|
||||||
|
/// # struct Data;
|
||||||
|
/// # trait Source: CastFrom {}
|
||||||
|
/// # trait Greet {
|
||||||
|
/// # fn greet(&self);
|
||||||
|
/// # }
|
||||||
|
/// # impl Greet for Data {
|
||||||
|
/// # fn greet(&self) {
|
||||||
|
/// # println!("Hello");
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// impl Source for Data {}
|
||||||
|
/// let data = Data;
|
||||||
|
/// let source: &dyn Source = &data;
|
||||||
|
/// assert!(source.impls::<dyn Greet>());
|
||||||
|
/// assert!(!source.impls::<dyn std::fmt::Debug>());
|
||||||
|
/// ```
|
||||||
|
pub trait CastRef {
|
||||||
|
/// Casts a reference to this trait into that of type `T`.
|
||||||
|
fn cast<T: ?Sized + 'static>(&self) -> Option<&T>;
|
||||||
|
|
||||||
|
/// Tests if this trait object can be cast into `T`.
|
||||||
|
fn impls<T: ?Sized + 'static>(&self) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A blanket implementation of `CastRef` for traits extending `CastFrom`.
|
||||||
|
impl<S: ?Sized + CastFrom> CastRef for S {
|
||||||
|
fn cast<T: ?Sized + 'static>(&self) -> Option<&T> {
|
||||||
|
let any = self.ref_any();
|
||||||
|
// 获取从 self 到 T 的转换器,如果不存在则返回 None
|
||||||
|
let caster = caster::<T>(any.type_id())?;
|
||||||
|
(caster.cast_ref)(any).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "none"))]
|
||||||
|
fn impls<T: ?Sized + 'static>(&self) -> bool {
|
||||||
|
use crate::CASTER_MAP;
|
||||||
|
CASTER_MAP.contains_key(&(self.type_id(), TypeId::of::<Caster<T>>()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "none")]
|
||||||
|
fn impls<T: ?Sized + 'static>(&self) -> bool {
|
||||||
|
use crate::caster_map;
|
||||||
|
|
||||||
|
caster_map().contains_key(&(self.type_id(), TypeId::of::<Caster<T>>()))
|
||||||
|
}
|
||||||
|
}
|
28
kernel/src/libs/intertrait/src/hasher.rs
Normal file
28
kernel/src/libs/intertrait/src/hasher.rs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
use core::convert::TryInto;
|
||||||
|
use core::hash::{BuildHasherDefault, Hasher};
|
||||||
|
use core::mem::size_of;
|
||||||
|
|
||||||
|
/// A simple `Hasher` implementation tuned for performance.
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct FastHasher(u64);
|
||||||
|
|
||||||
|
/// A `BuildHasher` for `FastHasher`.
|
||||||
|
pub type BuildFastHasher = BuildHasherDefault<FastHasher>;
|
||||||
|
|
||||||
|
impl Hasher for FastHasher {
|
||||||
|
fn finish(&self) -> u64 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&mut self, bytes: &[u8]) {
|
||||||
|
let mut bytes = bytes;
|
||||||
|
while bytes.len() > size_of::<u64>() {
|
||||||
|
let (u64_bytes, remaining) = bytes.split_at(size_of::<u64>());
|
||||||
|
self.0 ^= u64::from_ne_bytes(u64_bytes.try_into().unwrap());
|
||||||
|
bytes = remaining
|
||||||
|
}
|
||||||
|
self.0 ^= bytes
|
||||||
|
.iter()
|
||||||
|
.fold(0u64, |result, b| (result << 8) | *b as u64);
|
||||||
|
}
|
||||||
|
}
|
584
kernel/src/libs/intertrait/src/lib.rs
Normal file
584
kernel/src/libs/intertrait/src/lib.rs
Normal file
@ -0,0 +1,584 @@
|
|||||||
|
//! A library providing direct casting among trait objects implemented by a 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) is possible
|
||||||
|
//! (even no coercion from a trait object to that of 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.
|
||||||
|
//!
|
||||||
|
//! # Usage
|
||||||
|
//! ```
|
||||||
|
//! use intertrait::*;
|
||||||
|
//! use intertrait::cast::*;
|
||||||
|
//!
|
||||||
|
//! struct Data;
|
||||||
|
//!
|
||||||
|
//! trait Source: CastFrom {}
|
||||||
|
//!
|
||||||
|
//! trait Greet {
|
||||||
|
//! fn greet(&self);
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! #[cast_to]
|
||||||
|
//! impl Greet for Data {
|
||||||
|
//! fn greet(&self) {
|
||||||
|
//! println!("Hello");
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! impl Source for Data {}
|
||||||
|
//!
|
||||||
|
//! let data = Data;
|
||||||
|
//! let source: &dyn Source = &data;
|
||||||
|
//! let greet = source.cast::<dyn Greet>();
|
||||||
|
//! greet.unwrap().greet();
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Target traits must be explicitly designated beforehand. There are three ways to do it:
|
||||||
|
//!
|
||||||
|
//! * [`#[cast_to]`][cast_to] to `impl` item
|
||||||
|
//! * [`#[cast_to(Trait)]`][cast_to] to type definition
|
||||||
|
//! * [`castable_to!(Type => Trait1, Trait2)`][castable_to]
|
||||||
|
//!
|
||||||
|
//! 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
|
||||||
|
|
||||||
|
#![cfg_attr(target_os = "none", no_std)]
|
||||||
|
|
||||||
|
extern crate alloc;
|
||||||
|
extern crate core;
|
||||||
|
|
||||||
|
use core::{
|
||||||
|
any::{Any, TypeId},
|
||||||
|
marker::{Send, Sync},
|
||||||
|
};
|
||||||
|
|
||||||
|
use alloc::boxed::Box;
|
||||||
|
use alloc::rc::Rc;
|
||||||
|
use alloc::sync::Arc;
|
||||||
|
|
||||||
|
use hashbrown::HashMap;
|
||||||
|
use linkme::distributed_slice;
|
||||||
|
|
||||||
|
pub use intertrait_macros::*;
|
||||||
|
|
||||||
|
use crate::hasher::BuildFastHasher;
|
||||||
|
|
||||||
|
pub mod cast;
|
||||||
|
mod hasher;
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub type BoxedCaster = Box<dyn Any + Send + Sync>;
|
||||||
|
|
||||||
|
#[cfg(doctest)]
|
||||||
|
doc_comment::doctest!("../README.md");
|
||||||
|
|
||||||
|
/// A distributed slice gathering constructor functions for [`Caster<T>`]s.
|
||||||
|
///
|
||||||
|
/// A constructor function returns `TypeId` of a concrete type involved in the casting
|
||||||
|
/// and a `Box` of a trait object backed by a [`Caster<T>`].
|
||||||
|
///
|
||||||
|
/// [`Caster<T>`]: ./struct.Caster.html
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[distributed_slice]
|
||||||
|
pub static CASTERS: [fn() -> (TypeId, BoxedCaster)] = [..];
|
||||||
|
|
||||||
|
/// A `HashMap` mapping `TypeId` of a [`Caster<T>`] to an instance of it.
|
||||||
|
///
|
||||||
|
/// [`Caster<T>`]: ./struct.Caster.html
|
||||||
|
#[cfg(not(target_os = "none"))]
|
||||||
|
static CASTER_MAP: once_cell::sync::Lazy<HashMap<(TypeId, TypeId), BoxedCaster, BuildFastHasher>> =
|
||||||
|
once_cell::sync::Lazy::new(|| {
|
||||||
|
CASTERS
|
||||||
|
.iter()
|
||||||
|
.map(|f| {
|
||||||
|
let (type_id, caster) = f();
|
||||||
|
((type_id, (*caster).type_id()), caster)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
});
|
||||||
|
|
||||||
|
/// CasterMap
|
||||||
|
///
|
||||||
|
/// key.0: type_id of source
|
||||||
|
/// key.1: type_id of target
|
||||||
|
///
|
||||||
|
/// value: A BoxedCaster which can cast source to target
|
||||||
|
#[cfg(target_os = "none")]
|
||||||
|
static mut CASTER_MAP: Option<HashMap<(TypeId, TypeId), BoxedCaster, BuildFastHasher>> = None;
|
||||||
|
|
||||||
|
#[cfg(target_os = "none")]
|
||||||
|
pub fn caster_map() -> &'static HashMap<(TypeId, TypeId), BoxedCaster, BuildFastHasher> {
|
||||||
|
return unsafe {
|
||||||
|
CASTER_MAP.as_ref().unwrap_or_else(|| {
|
||||||
|
panic!("intertrait_caster_map() must be called after CASTER_MAP is initialized")
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initializes the global [`CASTER_MAP`] with [`CASTERS`].
|
||||||
|
///
|
||||||
|
/// no_std环境下,需要手动调用此函数初始化CASTER_MAP
|
||||||
|
#[cfg(target_os = "none")]
|
||||||
|
pub fn init_caster_map() {
|
||||||
|
use core::sync::atomic::AtomicBool;
|
||||||
|
|
||||||
|
let pd = AtomicBool::new(false);
|
||||||
|
let r = pd.compare_exchange(
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
core::sync::atomic::Ordering::SeqCst,
|
||||||
|
core::sync::atomic::Ordering::SeqCst,
|
||||||
|
);
|
||||||
|
|
||||||
|
if r.is_err() {
|
||||||
|
panic!("init_caster_map() must be called only once");
|
||||||
|
}
|
||||||
|
|
||||||
|
let hashmap = CASTERS
|
||||||
|
.iter()
|
||||||
|
.map(|f| {
|
||||||
|
let (type_id, caster) = f();
|
||||||
|
((type_id, (*caster).type_id()), caster)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
unsafe { CASTER_MAP = Some(hashmap) };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cast_arc_panic<T: ?Sized + 'static>(_: Arc<dyn Any + Sync + Send>) -> Arc<T> {
|
||||||
|
panic!("Prepend [sync] to the list of target traits for Sync + Send types")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 an immutable reference to a trait object for `Any` to a reference
|
||||||
|
/// to a trait object for trait `T`.
|
||||||
|
pub cast_ref: fn(from: &dyn Any) -> &T,
|
||||||
|
|
||||||
|
/// Casts a mutable reference to a trait object for `Any` to a mutable reference
|
||||||
|
/// to a trait object for trait `T`.
|
||||||
|
pub cast_mut: fn(from: &mut dyn Any) -> &mut T,
|
||||||
|
|
||||||
|
/// Casts a `Box` holding a trait object for `Any` to another `Box` holding a trait object
|
||||||
|
/// for trait `T`.
|
||||||
|
pub cast_box: fn(from: Box<dyn Any>) -> Box<T>,
|
||||||
|
|
||||||
|
/// Casts an `Rc` holding a trait object for `Any` to another `Rc` holding a trait object
|
||||||
|
/// for trait `T`.
|
||||||
|
pub cast_rc: fn(from: Rc<dyn Any>) -> Rc<T>,
|
||||||
|
|
||||||
|
/// Casts an `Arc` holding a trait object for `Any + Sync + Send + 'static`
|
||||||
|
/// to another `Arc` holding a trait object for trait `T`.
|
||||||
|
pub cast_arc: fn(from: Arc<dyn Any + Sync + Send + 'static>) -> Arc<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + 'static> Caster<T> {
|
||||||
|
pub fn new(
|
||||||
|
cast_ref: fn(from: &dyn Any) -> &T,
|
||||||
|
cast_mut: fn(from: &mut dyn Any) -> &mut T,
|
||||||
|
cast_box: fn(from: Box<dyn Any>) -> Box<T>,
|
||||||
|
cast_rc: fn(from: Rc<dyn Any>) -> Rc<T>,
|
||||||
|
) -> Caster<T> {
|
||||||
|
Caster::<T> {
|
||||||
|
cast_ref,
|
||||||
|
cast_mut,
|
||||||
|
cast_box,
|
||||||
|
cast_rc,
|
||||||
|
cast_arc: cast_arc_panic,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_sync(
|
||||||
|
cast_ref: fn(from: &dyn Any) -> &T,
|
||||||
|
cast_mut: fn(from: &mut dyn Any) -> &mut T,
|
||||||
|
cast_box: fn(from: Box<dyn Any>) -> Box<T>,
|
||||||
|
cast_rc: fn(from: Rc<dyn Any>) -> Rc<T>,
|
||||||
|
cast_arc: fn(from: Arc<dyn Any + Sync + Send>) -> Arc<T>,
|
||||||
|
) -> Caster<T> {
|
||||||
|
Caster::<T> {
|
||||||
|
cast_ref,
|
||||||
|
cast_mut,
|
||||||
|
cast_box,
|
||||||
|
cast_rc,
|
||||||
|
cast_arc,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a `Caster<S, T>` from a concrete type `S` to a trait `T` implemented by it.
|
||||||
|
///
|
||||||
|
/// ## 参数
|
||||||
|
///
|
||||||
|
/// - type_id: 源类型的type_id
|
||||||
|
///
|
||||||
|
/// T: 目标trait
|
||||||
|
fn caster<T: ?Sized + 'static>(type_id: TypeId) -> Option<&'static Caster<T>> {
|
||||||
|
#[cfg(not(target_os = "none"))]
|
||||||
|
{
|
||||||
|
CASTER_MAP
|
||||||
|
.get(&(type_id, TypeId::of::<Caster<T>>()))
|
||||||
|
.and_then(|caster| caster.downcast_ref::<Caster<T>>())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "none")]
|
||||||
|
{
|
||||||
|
caster_map()
|
||||||
|
.get(&(type_id, TypeId::of::<Caster<T>>()))
|
||||||
|
.and_then(|caster| caster.downcast_ref::<Caster<T>>())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `CastFrom` must be extended by a trait that wants to allow for casting into another trait.
|
||||||
|
///
|
||||||
|
/// It is used for obtaining a trait object for [`Any`] from a trait object for its sub-trait,
|
||||||
|
/// and blanket implemented for all `Sized + Any + 'static` types.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ```ignore
|
||||||
|
/// trait Source: CastFrom {
|
||||||
|
/// ...
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub trait CastFrom: Any + 'static {
|
||||||
|
/// Returns a immutable reference to `Any`, which is backed by the type implementing this trait.
|
||||||
|
fn ref_any(&self) -> &dyn Any;
|
||||||
|
|
||||||
|
/// Returns a mutable reference to `Any`, which is backed by the type implementing this trait.
|
||||||
|
fn mut_any(&mut self) -> &mut dyn Any;
|
||||||
|
|
||||||
|
/// Returns a `Box` of `Any`, which is backed by the type implementing this trait.
|
||||||
|
fn box_any(self: Box<Self>) -> Box<dyn Any>;
|
||||||
|
|
||||||
|
/// Returns an `Rc` of `Any`, which is backed by the type implementing this trait.
|
||||||
|
fn rc_any(self: Rc<Self>) -> Rc<dyn Any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `CastFromSync` must be extended by a trait that is `Any + Sync + Send + 'static`
|
||||||
|
/// and wants to allow for casting into another trait behind references and smart pointers
|
||||||
|
/// especially including `Arc`.
|
||||||
|
///
|
||||||
|
/// It is used for obtaining a trait object for [`Any + Sync + Send + 'static`] from an object
|
||||||
|
/// for its sub-trait, and blanket implemented for all `Sized + Sync + Send + 'static` types.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ```ignore
|
||||||
|
/// trait Source: CastFromSync {
|
||||||
|
/// ...
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub trait CastFromSync: CastFrom + Sync + Send + 'static {
|
||||||
|
fn arc_any(self: Arc<Self>) -> Arc<dyn Any + Sync + Send + 'static>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Sized + Any + 'static> CastFrom for T {
|
||||||
|
fn ref_any(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mut_any(&mut self) -> &mut dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn box_any(self: Box<Self>) -> Box<dyn Any> {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rc_any(self: Rc<Self>) -> Rc<dyn Any> {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CastFrom for dyn Any + 'static {
|
||||||
|
fn ref_any(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mut_any(&mut self) -> &mut dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn box_any(self: Box<Self>) -> Box<dyn Any> {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rc_any(self: Rc<Self>) -> Rc<dyn Any> {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Sized + Sync + Send + 'static> CastFromSync for T {
|
||||||
|
fn arc_any(self: Arc<Self>) -> Arc<dyn Any + Sync + Send + 'static> {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CastFrom for dyn Any + Sync + Send + 'static {
|
||||||
|
fn ref_any(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mut_any(&mut self) -> &mut dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn box_any(self: Box<Self>) -> Box<dyn Any> {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rc_any(self: Rc<Self>) -> Rc<dyn Any> {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CastFromSync for dyn Any + Sync + Send + 'static {
|
||||||
|
fn arc_any(self: Arc<Self>) -> Arc<dyn Any + Sync + Send + 'static> {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
extern crate std;
|
||||||
|
use std::any::{Any, TypeId};
|
||||||
|
use std::fmt::{Debug, Display};
|
||||||
|
|
||||||
|
use linkme::distributed_slice;
|
||||||
|
|
||||||
|
use crate::{BoxedCaster, CastFromSync};
|
||||||
|
|
||||||
|
use super::cast::*;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[distributed_slice(super::CASTERS)]
|
||||||
|
static TEST_CASTER: fn() -> (TypeId, BoxedCaster) = create_test_caster;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct TestStruct;
|
||||||
|
|
||||||
|
trait SourceTrait: CastFromSync {}
|
||||||
|
|
||||||
|
impl SourceTrait for TestStruct {}
|
||||||
|
|
||||||
|
fn create_test_caster() -> (TypeId, BoxedCaster) {
|
||||||
|
let type_id = TypeId::of::<TestStruct>();
|
||||||
|
let caster = Box::new(Caster::<dyn Debug> {
|
||||||
|
cast_ref: |from| from.downcast_ref::<TestStruct>().unwrap(),
|
||||||
|
cast_mut: |from| from.downcast_mut::<TestStruct>().unwrap(),
|
||||||
|
cast_box: |from| from.downcast::<TestStruct>().unwrap(),
|
||||||
|
cast_rc: |from| from.downcast::<TestStruct>().unwrap(),
|
||||||
|
cast_arc: |from| from.downcast::<TestStruct>().unwrap(),
|
||||||
|
});
|
||||||
|
(type_id, caster)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cast_ref() {
|
||||||
|
let ts = TestStruct;
|
||||||
|
let st: &dyn SourceTrait = &ts;
|
||||||
|
let debug = st.cast::<dyn Debug>();
|
||||||
|
assert!(debug.is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cast_mut() {
|
||||||
|
let mut ts = TestStruct;
|
||||||
|
let st: &mut dyn SourceTrait = &mut ts;
|
||||||
|
let debug = st.cast::<dyn Debug>();
|
||||||
|
assert!(debug.is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cast_box() {
|
||||||
|
let ts = Box::new(TestStruct);
|
||||||
|
let st: Box<dyn SourceTrait> = ts;
|
||||||
|
let debug = st.cast::<dyn Debug>();
|
||||||
|
assert!(debug.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cast_rc() {
|
||||||
|
let ts = Rc::new(TestStruct);
|
||||||
|
let st: Rc<dyn SourceTrait> = ts;
|
||||||
|
let debug = st.cast::<dyn Debug>();
|
||||||
|
assert!(debug.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cast_arc() {
|
||||||
|
let ts = Arc::new(TestStruct);
|
||||||
|
let st: Arc<dyn SourceTrait> = ts;
|
||||||
|
let debug = st.cast::<dyn Debug>();
|
||||||
|
assert!(debug.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cast_ref_wrong() {
|
||||||
|
let ts = TestStruct;
|
||||||
|
let st: &dyn SourceTrait = &ts;
|
||||||
|
let display = st.cast::<dyn Display>();
|
||||||
|
assert!(display.is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cast_mut_wrong() {
|
||||||
|
let mut ts = TestStruct;
|
||||||
|
let st: &mut dyn SourceTrait = &mut ts;
|
||||||
|
let display = st.cast::<dyn Display>();
|
||||||
|
assert!(display.is_none());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cast_box_wrong() {
|
||||||
|
let ts = Box::new(TestStruct);
|
||||||
|
let st: Box<dyn SourceTrait> = ts;
|
||||||
|
let display = st.cast::<dyn Display>();
|
||||||
|
assert!(display.is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cast_rc_wrong() {
|
||||||
|
let ts = Rc::new(TestStruct);
|
||||||
|
let st: Rc<dyn SourceTrait> = ts;
|
||||||
|
let display = st.cast::<dyn Display>();
|
||||||
|
assert!(display.is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cast_arc_wrong() {
|
||||||
|
let ts = Arc::new(TestStruct);
|
||||||
|
let st: Arc<dyn SourceTrait> = ts;
|
||||||
|
let display = st.cast::<dyn Display>();
|
||||||
|
assert!(display.is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cast_ref_from_any() {
|
||||||
|
let ts = TestStruct;
|
||||||
|
let st: &dyn Any = &ts;
|
||||||
|
let debug = st.cast::<dyn Debug>();
|
||||||
|
assert!(debug.is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cast_mut_from_any() {
|
||||||
|
let mut ts = TestStruct;
|
||||||
|
let st: &mut dyn Any = &mut ts;
|
||||||
|
let debug = st.cast::<dyn Debug>();
|
||||||
|
assert!(debug.is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cast_box_from_any() {
|
||||||
|
let ts = Box::new(TestStruct);
|
||||||
|
let st: Box<dyn Any> = ts;
|
||||||
|
let debug = st.cast::<dyn Debug>();
|
||||||
|
assert!(debug.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cast_rc_from_any() {
|
||||||
|
let ts = Rc::new(TestStruct);
|
||||||
|
let st: Rc<dyn Any> = ts;
|
||||||
|
let debug = st.cast::<dyn Debug>();
|
||||||
|
assert!(debug.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cast_arc_from_any() {
|
||||||
|
let ts = Arc::new(TestStruct);
|
||||||
|
let st: Arc<dyn Any + Send + Sync> = ts;
|
||||||
|
let debug = st.cast::<dyn Debug>();
|
||||||
|
assert!(debug.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn impls_ref() {
|
||||||
|
let ts = TestStruct;
|
||||||
|
let st: &dyn SourceTrait = &ts;
|
||||||
|
assert!(st.impls::<dyn Debug>());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn impls_mut() {
|
||||||
|
let mut ts = TestStruct;
|
||||||
|
let st: &mut dyn SourceTrait = &mut ts;
|
||||||
|
assert!((*st).impls::<dyn Debug>());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn impls_box() {
|
||||||
|
let ts = Box::new(TestStruct);
|
||||||
|
let st: Box<dyn SourceTrait> = ts;
|
||||||
|
assert!((*st).impls::<dyn Debug>());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn impls_rc() {
|
||||||
|
let ts = Rc::new(TestStruct);
|
||||||
|
let st: Rc<dyn SourceTrait> = ts;
|
||||||
|
assert!((*st).impls::<dyn Debug>());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn impls_arc() {
|
||||||
|
let ts = Arc::new(TestStruct);
|
||||||
|
let st: Arc<dyn SourceTrait> = ts;
|
||||||
|
assert!((*st).impls::<dyn Debug>());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn impls_not_ref() {
|
||||||
|
let ts = TestStruct;
|
||||||
|
let st: &dyn SourceTrait = &ts;
|
||||||
|
assert!(!st.impls::<dyn Display>());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn impls_not_mut() {
|
||||||
|
let mut ts = TestStruct;
|
||||||
|
let st: &mut dyn Any = &mut ts;
|
||||||
|
assert!(!(*st).impls::<dyn Display>());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn impls_not_box() {
|
||||||
|
let ts = Box::new(TestStruct);
|
||||||
|
let st: Box<dyn SourceTrait> = ts;
|
||||||
|
assert!(!st.impls::<dyn Display>());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn impls_not_rc() {
|
||||||
|
let ts = Rc::new(TestStruct);
|
||||||
|
let st: Rc<dyn SourceTrait> = ts;
|
||||||
|
assert!(!(*st).impls::<dyn Display>());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn impls_not_arc() {
|
||||||
|
let ts = Arc::new(TestStruct);
|
||||||
|
let st: Arc<dyn SourceTrait> = ts;
|
||||||
|
assert!(!(*st).impls::<dyn Display>());
|
||||||
|
}
|
||||||
|
}
|
55
kernel/src/libs/intertrait/tests/castable_to.rs
Normal file
55
kernel/src/libs/intertrait/tests/castable_to.rs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
use intertrait::cast::*;
|
||||||
|
use intertrait::*;
|
||||||
|
|
||||||
|
struct Data;
|
||||||
|
|
||||||
|
trait Source: CastFrom {}
|
||||||
|
|
||||||
|
trait Greet {
|
||||||
|
fn greet(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Greet for Data {
|
||||||
|
fn greet(&self) {
|
||||||
|
println!("Hello");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Greet1 {
|
||||||
|
fn greet1(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Greet1 for Data {
|
||||||
|
fn greet1(&self) {
|
||||||
|
println!("Hello1");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Greet2 {
|
||||||
|
fn greet2(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Greet2 for Data {
|
||||||
|
fn greet2(&self) {
|
||||||
|
println!("Hello2");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Source for Data {}
|
||||||
|
|
||||||
|
castable_to! { Data => crate::Greet, Greet1, Greet2 }
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_multi_traits_on_struct() {
|
||||||
|
let data = Data;
|
||||||
|
let source: &dyn Source = &data;
|
||||||
|
|
||||||
|
let greet = source.cast::<dyn Greet>();
|
||||||
|
greet.unwrap().greet();
|
||||||
|
|
||||||
|
let greet1 = source.cast::<dyn Greet1>();
|
||||||
|
greet1.unwrap().greet1();
|
||||||
|
|
||||||
|
let greet2 = source.cast::<dyn Greet2>();
|
||||||
|
greet2.unwrap().greet2();
|
||||||
|
}
|
31
kernel/src/libs/intertrait/tests/on-enum.rs
Normal file
31
kernel/src/libs/intertrait/tests/on-enum.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
use intertrait::cast::*;
|
||||||
|
use intertrait::*;
|
||||||
|
|
||||||
|
#[cast_to(Greet)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
enum Data {
|
||||||
|
Var1,
|
||||||
|
Var2(u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Source: CastFrom {}
|
||||||
|
|
||||||
|
trait Greet {
|
||||||
|
fn greet(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Greet for Data {
|
||||||
|
fn greet(&self) {
|
||||||
|
println!("Hello");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Source for Data {}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cast_to_on_enum() {
|
||||||
|
let data = Data::Var2(1);
|
||||||
|
let source: &dyn Source = &data;
|
||||||
|
let greet = source.cast::<dyn Greet>();
|
||||||
|
greet.unwrap().greet();
|
||||||
|
}
|
27
kernel/src/libs/intertrait/tests/on-struct.rs
Normal file
27
kernel/src/libs/intertrait/tests/on-struct.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
use intertrait::cast::*;
|
||||||
|
use intertrait::*;
|
||||||
|
|
||||||
|
#[cast_to(Greet)]
|
||||||
|
struct Data;
|
||||||
|
|
||||||
|
trait Source: CastFrom {}
|
||||||
|
|
||||||
|
trait Greet {
|
||||||
|
fn greet(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Greet for Data {
|
||||||
|
fn greet(&self) {
|
||||||
|
println!("Hello");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Source for Data {}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cast_to_on_struct() {
|
||||||
|
let data = Data;
|
||||||
|
let source: &dyn Source = &data;
|
||||||
|
let greet = source.cast::<dyn Greet>();
|
||||||
|
greet.unwrap().greet();
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
use intertrait::cast::*;
|
||||||
|
use intertrait::*;
|
||||||
|
|
||||||
|
struct I32Data(i32);
|
||||||
|
|
||||||
|
trait Source: CastFrom {}
|
||||||
|
|
||||||
|
trait Producer {
|
||||||
|
type Output: Debug;
|
||||||
|
|
||||||
|
fn produce(&self) -> Self::Output;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cast_to]
|
||||||
|
impl Producer for I32Data {
|
||||||
|
type Output = i32;
|
||||||
|
|
||||||
|
fn produce(&self) -> Self::Output {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Source for I32Data {}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cast_to_on_trait_impl_with_assoc_type1() {
|
||||||
|
let data = I32Data(100);
|
||||||
|
let source: &dyn Source = &data;
|
||||||
|
let producer = source.cast::<dyn Producer<Output = i32>>();
|
||||||
|
assert_eq!(producer.unwrap().produce(), data.0);
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
use intertrait::cast::*;
|
||||||
|
use intertrait::*;
|
||||||
|
|
||||||
|
struct Data;
|
||||||
|
|
||||||
|
trait Source: CastFrom {}
|
||||||
|
|
||||||
|
trait Concat {
|
||||||
|
type I1: Debug;
|
||||||
|
type I2: Debug;
|
||||||
|
|
||||||
|
fn concat(&self, a: Self::I1, b: Self::I2) -> String;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cast_to]
|
||||||
|
impl Concat for Data {
|
||||||
|
type I1 = i32;
|
||||||
|
type I2 = &'static str;
|
||||||
|
|
||||||
|
fn concat(&self, a: Self::I1, b: Self::I2) -> String {
|
||||||
|
format!("Data: {} - {}", a, b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Source for Data {}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cast_to_on_trait_impl_with_assoc_type2() {
|
||||||
|
let data = Data;
|
||||||
|
let source: &dyn Source = &data;
|
||||||
|
let concat = source.cast::<dyn Concat<I1 = i32, I2 = &'static str>>();
|
||||||
|
assert_eq!(concat.unwrap().concat(101, "hello"), "Data: 101 - hello");
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
use intertrait::cast::*;
|
||||||
|
use intertrait::*;
|
||||||
|
|
||||||
|
struct Data;
|
||||||
|
|
||||||
|
trait Source: CastFrom {}
|
||||||
|
|
||||||
|
trait Concat<T: Debug> {
|
||||||
|
type I1: Debug;
|
||||||
|
type I2: Debug;
|
||||||
|
|
||||||
|
fn concat(&self, prefix: T, a: Self::I1, b: Self::I2) -> String;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cast_to]
|
||||||
|
impl Concat<String> for Data {
|
||||||
|
type I1 = i32;
|
||||||
|
type I2 = &'static str;
|
||||||
|
|
||||||
|
fn concat(&self, prefix: String, a: Self::I1, b: Self::I2) -> String {
|
||||||
|
format!("{}: {} - {}", prefix, a, b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Source for Data {}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cast_to_on_trait_impl_with_assoc_type3() {
|
||||||
|
let data = Data;
|
||||||
|
let source: &dyn Source = &data;
|
||||||
|
let concat = source.cast::<dyn Concat<String, I1 = i32, I2 = &'static str>>();
|
||||||
|
assert_eq!(
|
||||||
|
concat.unwrap().concat("Data".to_owned(), 101, "hello"),
|
||||||
|
"Data: 101 - hello"
|
||||||
|
);
|
||||||
|
}
|
27
kernel/src/libs/intertrait/tests/on-trait-impl.rs
Normal file
27
kernel/src/libs/intertrait/tests/on-trait-impl.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
use intertrait::cast::*;
|
||||||
|
use intertrait::*;
|
||||||
|
|
||||||
|
struct Data;
|
||||||
|
|
||||||
|
trait Source: CastFrom {}
|
||||||
|
|
||||||
|
trait Greet {
|
||||||
|
fn greet(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cast_to]
|
||||||
|
impl Greet for Data {
|
||||||
|
fn greet(&self) {
|
||||||
|
println!("Hello");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Source for Data {}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cast_to_on_trait_impl() {
|
||||||
|
let data = Data;
|
||||||
|
let source: &dyn Source = &data;
|
||||||
|
let greet = source.cast::<dyn Greet>();
|
||||||
|
greet.unwrap().greet();
|
||||||
|
}
|
54
kernel/src/libs/intertrait/tests/on-type-multi-traits.rs
Normal file
54
kernel/src/libs/intertrait/tests/on-type-multi-traits.rs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
use intertrait::cast::*;
|
||||||
|
use intertrait::*;
|
||||||
|
|
||||||
|
#[cast_to(Greet, Greet1, Greet2)]
|
||||||
|
struct Data;
|
||||||
|
|
||||||
|
trait Source: CastFrom {}
|
||||||
|
|
||||||
|
trait Greet {
|
||||||
|
fn greet(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Greet for Data {
|
||||||
|
fn greet(&self) {
|
||||||
|
println!("Hello");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Greet1 {
|
||||||
|
fn greet1(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Greet1 for Data {
|
||||||
|
fn greet1(&self) {
|
||||||
|
println!("Hello1");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Greet2 {
|
||||||
|
fn greet2(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Greet2 for Data {
|
||||||
|
fn greet2(&self) {
|
||||||
|
println!("Hello2");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Source for Data {}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_multi_traits_on_struct() {
|
||||||
|
let data = Data;
|
||||||
|
let source: &dyn Source = &data;
|
||||||
|
|
||||||
|
let greet = source.cast::<dyn Greet>();
|
||||||
|
greet.unwrap().greet();
|
||||||
|
|
||||||
|
let greet1 = source.cast::<dyn Greet1>();
|
||||||
|
greet1.unwrap().greet1();
|
||||||
|
|
||||||
|
let greet2 = source.cast::<dyn Greet2>();
|
||||||
|
greet2.unwrap().greet2();
|
||||||
|
}
|
5
kernel/src/libs/intertrait/tests/run.rs
Normal file
5
kernel/src/libs/intertrait/tests/run.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#[test]
|
||||||
|
fn tests() {
|
||||||
|
let t = trybuild::TestCases::new();
|
||||||
|
t.compile_fail("tests/ui/*.rs");
|
||||||
|
}
|
27
kernel/src/libs/intertrait/tests/ui/duplicate-flags.rs
Normal file
27
kernel/src/libs/intertrait/tests/ui/duplicate-flags.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
use intertrait::cast::*;
|
||||||
|
use intertrait::*;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
#[cast_to([sync, sync] Greet)]
|
||||||
|
struct Data;
|
||||||
|
|
||||||
|
trait Source: CastFromSync {}
|
||||||
|
|
||||||
|
trait Greet {
|
||||||
|
fn greet(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Greet for Data {
|
||||||
|
fn greet(&self) {
|
||||||
|
println!("Hello");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Source for Data {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let data = Arc::new(Data);
|
||||||
|
let source: Arc<dyn Source> = data;
|
||||||
|
let greet = source.cast::<dyn Greet>();
|
||||||
|
greet.unwrap_or_else(|_| panic!("can't happen")).greet();
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
error: Duplicated flag: sync
|
||||||
|
--> $DIR/duplicate-flags.rs:5:18
|
||||||
|
|
|
||||||
|
5 | #[cast_to([sync, sync] Greet)]
|
||||||
|
| ^^^^
|
31
kernel/src/libs/intertrait/tests/ui/on-generic-type.rs
Normal file
31
kernel/src/libs/intertrait/tests/ui/on-generic-type.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
use intertrait::*;
|
||||||
|
use intertrait::cast::*;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
#[cast_to(Greet)]
|
||||||
|
struct Data<T: 'static> {
|
||||||
|
phantom: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Source: CastFrom {}
|
||||||
|
|
||||||
|
trait Greet {
|
||||||
|
fn greet(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: 'static> Greet for Data<T> {
|
||||||
|
fn greet(&self) {
|
||||||
|
println!("Hello");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: 'static> Source for Data<T> {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let data = Data::<i32> {
|
||||||
|
phantom: PhantomData,
|
||||||
|
};
|
||||||
|
let source: &dyn Source = &data;
|
||||||
|
let greet = source.cast::<dyn Greet>();
|
||||||
|
greet.unwrap().greet();
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
error: #[cast_to(..)] can't be used on a generic type definition
|
||||||
|
--> tests/ui/on-generic-type.rs:6:12
|
||||||
|
|
|
||||||
|
6 | struct Data<T: 'static> {
|
||||||
|
| ^^^^^^^^^^^^
|
14
kernel/src/libs/intertrait/tests/ui/on-type-impl.rs
Normal file
14
kernel/src/libs/intertrait/tests/ui/on-type-impl.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
use intertrait::*;
|
||||||
|
|
||||||
|
struct Data;
|
||||||
|
|
||||||
|
#[cast_to]
|
||||||
|
impl Data {
|
||||||
|
fn hello() {
|
||||||
|
println!("hello!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _ = Data;
|
||||||
|
}
|
5
kernel/src/libs/intertrait/tests/ui/on-type-impl.stderr
Normal file
5
kernel/src/libs/intertrait/tests/ui/on-type-impl.stderr
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
error: #[cast_to] should only be on an impl of a trait
|
||||||
|
--> $DIR/on-type-impl.rs:6:6
|
||||||
|
|
|
||||||
|
6 | impl Data {
|
||||||
|
| ^^^^
|
27
kernel/src/libs/intertrait/tests/ui/unknown-flag.rs
Normal file
27
kernel/src/libs/intertrait/tests/ui/unknown-flag.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
use intertrait::cast::*;
|
||||||
|
use intertrait::*;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
#[cast_to([sync, send] Greet)]
|
||||||
|
struct Data;
|
||||||
|
|
||||||
|
trait Source: CastFromSync {}
|
||||||
|
|
||||||
|
trait Greet {
|
||||||
|
fn greet(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Greet for Data {
|
||||||
|
fn greet(&self) {
|
||||||
|
println!("Hello");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Source for Data {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let data = Arc::new(Data);
|
||||||
|
let source: Arc<dyn Source> = data;
|
||||||
|
let greet = source.cast::<dyn Greet>();
|
||||||
|
greet.unwrap_or_else(|_| panic!("can't happen")).greet();
|
||||||
|
}
|
5
kernel/src/libs/intertrait/tests/ui/unknown-flag.stderr
Normal file
5
kernel/src/libs/intertrait/tests/ui/unknown-flag.stderr
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
error: Unknown flag: send
|
||||||
|
--> $DIR/unknown-flag.rs:5:18
|
||||||
|
|
|
||||||
|
5 | #[cast_to([sync, send] Greet)]
|
||||||
|
| ^^^^
|
@ -11,6 +11,7 @@ pub mod lib_ui;
|
|||||||
pub mod mutex;
|
pub mod mutex;
|
||||||
pub mod notifier;
|
pub mod notifier;
|
||||||
pub mod once;
|
pub mod once;
|
||||||
|
#[macro_use]
|
||||||
pub mod printk;
|
pub mod printk;
|
||||||
pub mod rbtree;
|
pub mod rbtree;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
@ -1416,10 +1416,12 @@ impl<K: Ord, V> RBTree<K, V> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_insert() {
|
fn test_insert() {
|
||||||
|
use crate::libs::rbtree::RBTree;
|
||||||
let mut m = RBTree::new();
|
let mut m = RBTree::new();
|
||||||
assert_eq!(m.len(), 0);
|
assert_eq!(m.len(), 0);
|
||||||
m.insert(1, 2);
|
m.insert(1, 2);
|
||||||
@ -1435,6 +1437,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_replace() {
|
fn test_replace() {
|
||||||
|
use crate::libs::rbtree::RBTree;
|
||||||
let mut m = RBTree::new();
|
let mut m = RBTree::new();
|
||||||
assert_eq!(m.len(), 0);
|
assert_eq!(m.len(), 0);
|
||||||
m.insert(2, 4);
|
m.insert(2, 4);
|
||||||
@ -1446,6 +1449,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_clone() {
|
fn test_clone() {
|
||||||
|
use crate::libs::rbtree::RBTree;
|
||||||
let mut m = RBTree::new();
|
let mut m = RBTree::new();
|
||||||
assert_eq!(m.len(), 0);
|
assert_eq!(m.len(), 0);
|
||||||
m.insert(1, 2);
|
m.insert(1, 2);
|
||||||
@ -1461,12 +1465,14 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_empty_remove() {
|
fn test_empty_remove() {
|
||||||
|
use crate::libs::rbtree::RBTree;
|
||||||
let mut m: RBTree<isize, bool> = RBTree::new();
|
let mut m: RBTree<isize, bool> = RBTree::new();
|
||||||
assert_eq!(m.remove(&0), None);
|
assert_eq!(m.remove(&0), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_empty_iter() {
|
fn test_empty_iter() {
|
||||||
|
use crate::libs::rbtree::RBTree;
|
||||||
let mut m: RBTree<isize, bool> = RBTree::new();
|
let mut m: RBTree<isize, bool> = RBTree::new();
|
||||||
assert_eq!(m.iter().next(), None);
|
assert_eq!(m.iter().next(), None);
|
||||||
assert_eq!(m.iter_mut().next(), None);
|
assert_eq!(m.iter_mut().next(), None);
|
||||||
@ -1477,6 +1483,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_lots_of_insertions() {
|
fn test_lots_of_insertions() {
|
||||||
|
use crate::libs::rbtree::RBTree;
|
||||||
let mut m = RBTree::new();
|
let mut m = RBTree::new();
|
||||||
|
|
||||||
// Try this a few times to make sure we never screw up the hashmap's
|
// Try this a few times to make sure we never screw up the hashmap's
|
||||||
@ -1540,6 +1547,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_find_mut() {
|
fn test_find_mut() {
|
||||||
|
use crate::libs::rbtree::RBTree;
|
||||||
let mut m = RBTree::new();
|
let mut m = RBTree::new();
|
||||||
m.insert(1, 12);
|
m.insert(1, 12);
|
||||||
m.insert(2, 8);
|
m.insert(2, 8);
|
||||||
@ -1554,6 +1562,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_remove() {
|
fn test_remove() {
|
||||||
|
use crate::libs::rbtree::RBTree;
|
||||||
let mut m = RBTree::new();
|
let mut m = RBTree::new();
|
||||||
m.insert(1, 2);
|
m.insert(1, 2);
|
||||||
assert_eq!(*m.get(&1).unwrap(), 2);
|
assert_eq!(*m.get(&1).unwrap(), 2);
|
||||||
@ -1571,6 +1580,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_is_empty() {
|
fn test_is_empty() {
|
||||||
|
use crate::libs::rbtree::RBTree;
|
||||||
let mut m = RBTree::new();
|
let mut m = RBTree::new();
|
||||||
m.insert(1, 2);
|
m.insert(1, 2);
|
||||||
assert!(!m.is_empty());
|
assert!(!m.is_empty());
|
||||||
@ -1580,6 +1590,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_pop() {
|
fn test_pop() {
|
||||||
|
use crate::libs::rbtree::RBTree;
|
||||||
let mut m = RBTree::new();
|
let mut m = RBTree::new();
|
||||||
m.insert(2, 4);
|
m.insert(2, 4);
|
||||||
m.insert(1, 2);
|
m.insert(1, 2);
|
||||||
@ -1595,6 +1606,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_iterate() {
|
fn test_iterate() {
|
||||||
|
use crate::libs::rbtree::RBTree;
|
||||||
let mut m = RBTree::new();
|
let mut m = RBTree::new();
|
||||||
for i in 0..32 {
|
for i in 0..32 {
|
||||||
m.insert(i, i * 2);
|
m.insert(i, i * 2);
|
||||||
@ -1612,6 +1624,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_keys() {
|
fn test_keys() {
|
||||||
|
use crate::libs::rbtree::RBTree;
|
||||||
let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
|
let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
|
||||||
let map: RBTree<_, _> = vec.into_iter().collect();
|
let map: RBTree<_, _> = vec.into_iter().collect();
|
||||||
let keys: Vec<_> = map.keys().cloned().collect();
|
let keys: Vec<_> = map.keys().cloned().collect();
|
||||||
@ -1623,6 +1636,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_values() {
|
fn test_values() {
|
||||||
|
use crate::libs::rbtree::RBTree;
|
||||||
let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
|
let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
|
||||||
let map: RBTree<_, _> = vec.into_iter().collect();
|
let map: RBTree<_, _> = vec.into_iter().collect();
|
||||||
let values: Vec<_> = map.values().cloned().collect();
|
let values: Vec<_> = map.values().cloned().collect();
|
||||||
@ -1634,6 +1648,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_values_mut() {
|
fn test_values_mut() {
|
||||||
|
use crate::libs::rbtree::RBTree;
|
||||||
let vec = vec![(1, 1), (2, 2), (3, 3)];
|
let vec = vec![(1, 1), (2, 2), (3, 3)];
|
||||||
let mut map: RBTree<_, _> = vec.into_iter().collect();
|
let mut map: RBTree<_, _> = vec.into_iter().collect();
|
||||||
for value in map.values_mut() {
|
for value in map.values_mut() {
|
||||||
@ -1648,6 +1663,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_find() {
|
fn test_find() {
|
||||||
|
use crate::libs::rbtree::RBTree;
|
||||||
let mut m = RBTree::new();
|
let mut m = RBTree::new();
|
||||||
assert!(m.get(&1).is_none());
|
assert!(m.get(&1).is_none());
|
||||||
m.insert(1, 2);
|
m.insert(1, 2);
|
||||||
@ -1659,6 +1675,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_eq() {
|
fn test_eq() {
|
||||||
|
use crate::libs::rbtree::RBTree;
|
||||||
let mut m1 = RBTree::new();
|
let mut m1 = RBTree::new();
|
||||||
m1.insert(1, 2);
|
m1.insert(1, 2);
|
||||||
m1.insert(2, 3);
|
m1.insert(2, 3);
|
||||||
@ -1677,6 +1694,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_show() {
|
fn test_show() {
|
||||||
|
use crate::libs::rbtree::RBTree;
|
||||||
let mut map = RBTree::new();
|
let mut map = RBTree::new();
|
||||||
let empty: RBTree<i32, i32> = RBTree::new();
|
let empty: RBTree<i32, i32> = RBTree::new();
|
||||||
|
|
||||||
@ -1691,6 +1709,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_from_iter() {
|
fn test_from_iter() {
|
||||||
|
use crate::libs::rbtree::RBTree;
|
||||||
let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
|
let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
|
||||||
|
|
||||||
let map: RBTree<_, _> = xs.iter().cloned().collect();
|
let map: RBTree<_, _> = xs.iter().cloned().collect();
|
||||||
@ -1702,6 +1721,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_size_hint() {
|
fn test_size_hint() {
|
||||||
|
use crate::libs::rbtree::RBTree;
|
||||||
let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
|
let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
|
||||||
|
|
||||||
let map: RBTree<_, _> = xs.iter().cloned().collect();
|
let map: RBTree<_, _> = xs.iter().cloned().collect();
|
||||||
@ -1715,6 +1735,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_iter_len() {
|
fn test_iter_len() {
|
||||||
|
use crate::libs::rbtree::RBTree;
|
||||||
let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
|
let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
|
||||||
|
|
||||||
let map: RBTree<_, _> = xs.iter().cloned().collect();
|
let map: RBTree<_, _> = xs.iter().cloned().collect();
|
||||||
@ -1728,6 +1749,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mut_size_hint() {
|
fn test_mut_size_hint() {
|
||||||
|
use crate::libs::rbtree::RBTree;
|
||||||
let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
|
let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
|
||||||
|
|
||||||
let mut map: RBTree<_, _> = xs.iter().cloned().collect();
|
let mut map: RBTree<_, _> = xs.iter().cloned().collect();
|
||||||
@ -1741,6 +1763,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_iter_mut_len() {
|
fn test_iter_mut_len() {
|
||||||
|
use crate::libs::rbtree::RBTree;
|
||||||
let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
|
let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
|
||||||
|
|
||||||
let mut map: RBTree<_, _> = xs.iter().cloned().collect();
|
let mut map: RBTree<_, _> = xs.iter().cloned().collect();
|
||||||
@ -1754,6 +1777,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_index() {
|
fn test_index() {
|
||||||
|
use crate::libs::rbtree::RBTree;
|
||||||
let mut map = RBTree::new();
|
let mut map = RBTree::new();
|
||||||
|
|
||||||
map.insert(1, 2);
|
map.insert(1, 2);
|
||||||
@ -1766,6 +1790,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn test_index_nonexistent() {
|
fn test_index_nonexistent() {
|
||||||
|
use crate::libs::rbtree::RBTree;
|
||||||
let mut map = RBTree::new();
|
let mut map = RBTree::new();
|
||||||
|
|
||||||
map.insert(1, 2);
|
map.insert(1, 2);
|
||||||
@ -1777,6 +1802,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_extend_iter() {
|
fn test_extend_iter() {
|
||||||
|
use crate::libs::rbtree::RBTree;
|
||||||
let mut a = RBTree::new();
|
let mut a = RBTree::new();
|
||||||
a.insert(1, "one");
|
a.insert(1, "one");
|
||||||
let mut b = RBTree::new();
|
let mut b = RBTree::new();
|
||||||
|
@ -38,6 +38,7 @@ extern void rs_softirq_init();
|
|||||||
extern void rs_mm_init();
|
extern void rs_mm_init();
|
||||||
extern int rs_video_init();
|
extern int rs_video_init();
|
||||||
extern void rs_kthread_init();
|
extern void rs_kthread_init();
|
||||||
|
extern void rs_init_intertrait();
|
||||||
|
|
||||||
ul bsp_idt_size, bsp_gdt_size;
|
ul bsp_idt_size, bsp_gdt_size;
|
||||||
|
|
||||||
@ -101,6 +102,7 @@ void system_initialize()
|
|||||||
scm_reinit();
|
scm_reinit();
|
||||||
rs_textui_init();
|
rs_textui_init();
|
||||||
|
|
||||||
|
rs_init_intertrait();
|
||||||
// kinfo("vaddr:%#018lx", video_frame_buffer_info.vaddr);
|
// kinfo("vaddr:%#018lx", video_frame_buffer_info.vaddr);
|
||||||
io_mfence();
|
io_mfence();
|
||||||
|
|
||||||
|
@ -95,6 +95,7 @@ unsafe impl GlobalAlloc for KernelAllocator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 内存分配错误处理函数
|
/// 内存分配错误处理函数
|
||||||
|
#[cfg(target_os = "none")]
|
||||||
#[alloc_error_handler]
|
#[alloc_error_handler]
|
||||||
pub fn global_alloc_err_handler(layout: Layout) -> ! {
|
pub fn global_alloc_err_handler(layout: Layout) -> ! {
|
||||||
panic!("global_alloc_error, layout: {:?}", layout);
|
panic!("global_alloc_error, layout: {:?}", layout);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user