引入intertrait库,支持trait之间的互相转换 (#395)

* 能过编译(test还没法跑)

* 初始化intertrait转换库

* update license of intertrait
This commit is contained in:
LoGin 2023-10-02 20:46:19 +08:00 committed by GitHub
parent bb0e4d4131
commit fba5623183
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 2211 additions and 2 deletions

View File

@ -181,5 +181,5 @@
"rust-analyzer.checkOnSave.allTargets": false,
"rust-analyzer.linkedProjects": [
"./kernel/Cargo.toml"
]
],
}

View File

@ -5,9 +5,13 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
crate-type = ["staticlib"]
[workspace]
members = [ "src/libs/intertrait" ]
# 运行时依赖项
[dependencies]
x86 = "0.52.0"
@ -28,6 +32,8 @@ memoffset = "0.9.0"
atomic_enum = "0.2.0"
raw-cpuid = "11.0.1"
acpi = "5.0.0"
intertrait = { path = "src/libs/intertrait" }
linkme = "0.2"
# 构建时依赖项
[build-dependencies]

View 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
View File

@ -0,0 +1,5 @@
pub mod c_adapter;
fn init_intertrait() {
intertrait::init_caster_map();
}

View File

@ -1,4 +1,3 @@
#![no_std] // <1>
#![no_main] // <1>
#![feature(alloc_error_handler)]
#![feature(allocator_api)]
@ -15,6 +14,11 @@
#![feature(trait_upcasting)]
#![feature(slice_ptr_get)]
#![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_camel_case_types)]
@ -31,6 +35,7 @@ mod include;
mod driver; // 如果driver依赖了libs应该在libs后面导出
mod exception;
mod filesystem;
mod init;
mod ipc;
mod mm;
mod net;
@ -53,6 +58,8 @@ extern crate num;
extern crate num_derive;
extern crate smoltcp;
extern crate thingbuf;
#[macro_use]
extern crate intertrait;
#[cfg(target_arch = "x86_64")]
extern crate x86;
@ -65,6 +72,7 @@ use crate::process::ProcessManager;
pub static KERNEL_ALLOCATOR: KernelAllocator = KernelAllocator;
/// 全局的panic处理函数
#[cfg(target_os = "none")]
#[panic_handler]
#[no_mangle]
pub fn panic(info: &PanicInfo) -> ! {

18
kernel/src/libs/intertrait/.gitignore vendored Normal file
View 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

View 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"

View 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.

View 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)

View 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"

View 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

View 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.

View 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()?,
})
}
}

View 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]) }
}

View 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
}

View 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
}
}

View 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()
}

View 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::*;

View 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),
}
}
}

View 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),
}
}
}

View 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()
}
}

View 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),
}
}
}

View 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>>()))
}
}

View 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);
}
}

View 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>());
}
}

View 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();
}

View 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();
}

View 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();
}

View File

@ -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);
}

View File

@ -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");
}

View File

@ -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"
);
}

View 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();
}

View 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();
}

View File

@ -0,0 +1,5 @@
#[test]
fn tests() {
let t = trybuild::TestCases::new();
t.compile_fail("tests/ui/*.rs");
}

View 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();
}

View File

@ -0,0 +1,5 @@
error: Duplicated flag: sync
--> $DIR/duplicate-flags.rs:5:18
|
5 | #[cast_to([sync, sync] Greet)]
| ^^^^

View 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();
}

View File

@ -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> {
| ^^^^^^^^^^^^

View File

@ -0,0 +1,14 @@
use intertrait::*;
struct Data;
#[cast_to]
impl Data {
fn hello() {
println!("hello!");
}
}
fn main() {
let _ = Data;
}

View 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 {
| ^^^^

View 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();
}

View File

@ -0,0 +1,5 @@
error: Unknown flag: send
--> $DIR/unknown-flag.rs:5:18
|
5 | #[cast_to([sync, send] Greet)]
| ^^^^

View File

@ -11,6 +11,7 @@ pub mod lib_ui;
pub mod mutex;
pub mod notifier;
pub mod once;
#[macro_use]
pub mod printk;
pub mod rbtree;
#[macro_use]

View File

@ -1416,10 +1416,12 @@ impl<K: Ord, V> RBTree<K, V> {
}
}
#[cfg(test)]
mod tests {
#[test]
fn test_insert() {
use crate::libs::rbtree::RBTree;
let mut m = RBTree::new();
assert_eq!(m.len(), 0);
m.insert(1, 2);
@ -1435,6 +1437,7 @@ mod tests {
#[test]
fn test_replace() {
use crate::libs::rbtree::RBTree;
let mut m = RBTree::new();
assert_eq!(m.len(), 0);
m.insert(2, 4);
@ -1446,6 +1449,7 @@ mod tests {
#[test]
fn test_clone() {
use crate::libs::rbtree::RBTree;
let mut m = RBTree::new();
assert_eq!(m.len(), 0);
m.insert(1, 2);
@ -1461,12 +1465,14 @@ mod tests {
#[test]
fn test_empty_remove() {
use crate::libs::rbtree::RBTree;
let mut m: RBTree<isize, bool> = RBTree::new();
assert_eq!(m.remove(&0), None);
}
#[test]
fn test_empty_iter() {
use crate::libs::rbtree::RBTree;
let mut m: RBTree<isize, bool> = RBTree::new();
assert_eq!(m.iter().next(), None);
assert_eq!(m.iter_mut().next(), None);
@ -1477,6 +1483,7 @@ mod tests {
#[test]
fn test_lots_of_insertions() {
use crate::libs::rbtree::RBTree;
let mut m = RBTree::new();
// Try this a few times to make sure we never screw up the hashmap's
@ -1540,6 +1547,7 @@ mod tests {
#[test]
fn test_find_mut() {
use crate::libs::rbtree::RBTree;
let mut m = RBTree::new();
m.insert(1, 12);
m.insert(2, 8);
@ -1554,6 +1562,7 @@ mod tests {
#[test]
fn test_remove() {
use crate::libs::rbtree::RBTree;
let mut m = RBTree::new();
m.insert(1, 2);
assert_eq!(*m.get(&1).unwrap(), 2);
@ -1571,6 +1580,7 @@ mod tests {
#[test]
fn test_is_empty() {
use crate::libs::rbtree::RBTree;
let mut m = RBTree::new();
m.insert(1, 2);
assert!(!m.is_empty());
@ -1580,6 +1590,7 @@ mod tests {
#[test]
fn test_pop() {
use crate::libs::rbtree::RBTree;
let mut m = RBTree::new();
m.insert(2, 4);
m.insert(1, 2);
@ -1595,6 +1606,7 @@ mod tests {
#[test]
fn test_iterate() {
use crate::libs::rbtree::RBTree;
let mut m = RBTree::new();
for i in 0..32 {
m.insert(i, i * 2);
@ -1612,6 +1624,7 @@ mod tests {
#[test]
fn test_keys() {
use crate::libs::rbtree::RBTree;
let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
let map: RBTree<_, _> = vec.into_iter().collect();
let keys: Vec<_> = map.keys().cloned().collect();
@ -1623,6 +1636,7 @@ mod tests {
#[test]
fn test_values() {
use crate::libs::rbtree::RBTree;
let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
let map: RBTree<_, _> = vec.into_iter().collect();
let values: Vec<_> = map.values().cloned().collect();
@ -1634,6 +1648,7 @@ mod tests {
#[test]
fn test_values_mut() {
use crate::libs::rbtree::RBTree;
let vec = vec![(1, 1), (2, 2), (3, 3)];
let mut map: RBTree<_, _> = vec.into_iter().collect();
for value in map.values_mut() {
@ -1648,6 +1663,7 @@ mod tests {
#[test]
fn test_find() {
use crate::libs::rbtree::RBTree;
let mut m = RBTree::new();
assert!(m.get(&1).is_none());
m.insert(1, 2);
@ -1659,6 +1675,7 @@ mod tests {
#[test]
fn test_eq() {
use crate::libs::rbtree::RBTree;
let mut m1 = RBTree::new();
m1.insert(1, 2);
m1.insert(2, 3);
@ -1677,6 +1694,7 @@ mod tests {
#[test]
fn test_show() {
use crate::libs::rbtree::RBTree;
let mut map = RBTree::new();
let empty: RBTree<i32, i32> = RBTree::new();
@ -1691,6 +1709,7 @@ mod tests {
#[test]
fn test_from_iter() {
use crate::libs::rbtree::RBTree;
let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
let map: RBTree<_, _> = xs.iter().cloned().collect();
@ -1702,6 +1721,7 @@ mod tests {
#[test]
fn test_size_hint() {
use crate::libs::rbtree::RBTree;
let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
let map: RBTree<_, _> = xs.iter().cloned().collect();
@ -1715,6 +1735,7 @@ mod tests {
#[test]
fn test_iter_len() {
use crate::libs::rbtree::RBTree;
let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
let map: RBTree<_, _> = xs.iter().cloned().collect();
@ -1728,6 +1749,7 @@ mod tests {
#[test]
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 mut map: RBTree<_, _> = xs.iter().cloned().collect();
@ -1741,6 +1763,7 @@ mod tests {
#[test]
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 mut map: RBTree<_, _> = xs.iter().cloned().collect();
@ -1754,6 +1777,7 @@ mod tests {
#[test]
fn test_index() {
use crate::libs::rbtree::RBTree;
let mut map = RBTree::new();
map.insert(1, 2);
@ -1766,6 +1790,7 @@ mod tests {
#[test]
#[should_panic]
fn test_index_nonexistent() {
use crate::libs::rbtree::RBTree;
let mut map = RBTree::new();
map.insert(1, 2);
@ -1777,6 +1802,7 @@ mod tests {
#[test]
fn test_extend_iter() {
use crate::libs::rbtree::RBTree;
let mut a = RBTree::new();
a.insert(1, "one");
let mut b = RBTree::new();

View File

@ -38,6 +38,7 @@ extern void rs_softirq_init();
extern void rs_mm_init();
extern int rs_video_init();
extern void rs_kthread_init();
extern void rs_init_intertrait();
ul bsp_idt_size, bsp_gdt_size;
@ -101,6 +102,7 @@ void system_initialize()
scm_reinit();
rs_textui_init();
rs_init_intertrait();
// kinfo("vaddr:%#018lx", video_frame_buffer_info.vaddr);
io_mfence();

View File

@ -95,6 +95,7 @@ unsafe impl GlobalAlloc for KernelAllocator {
}
/// 内存分配错误处理函数
#[cfg(target_os = "none")]
#[alloc_error_handler]
pub fn global_alloc_err_handler(layout: Layout) -> ! {
panic!("global_alloc_error, layout: {:?}", layout);