2 个版本
0.1.1 | 2024 年 7 月 2 日 |
---|---|
0.1.0 | 2024 年 5 月 2 日 |
#847 在 Rust 模式 中
每月 24 次下载
16KB
214 行
从 dyn Any
到其他 trait 对象的转换
no_std
no alloc 支持- 无 proc macros
- 无不安全代码
用法
[dependencies]
crosstrait = "0.1"
然后使用 register!{ 类型 => 特性 }
声明性宏和 Cast
特性。
对于嵌入式,链接器需要被告知类型注册表。
示例
use core::any::Any;
use crosstrait::{Cast, Castable, CastableRef, entry, register, REGISTRY, Registry};
// Some example traits to play with
use core::{fmt::{Debug, Formatter, Write}, ops::{AddAssign, SubAssign}};
// Add types and trait implementations to the default registry
// Implementation status is verified at compile time
register! { i32 => dyn Debug }
// Registering foreign types and traits works fine
// Serialization/deserialization of `dyn Any` is a major use case
// register! { i32 => dyn erased_serde::Serialize }
// If a type is not Send + Sync, it can't cast as Arc.
// `no_arc` accounts for that
register! { Formatter => dyn Write, no_arc }
// Check for trait impl registration on concrete type
assert!(i32::castable::<dyn Debug>());
// Check for trait impl registration on Any
let any: &dyn Any = &42i32;
assert!(any.castable::<dyn Debug>());
// SubAssign<i32> is impl'd for i32 but not registered
assert!(!any.castable::<dyn SubAssign<i32>>());
// Cast ref
let a: &dyn Debug = any.cast().unwrap();
println!("42 = {a:?}");
// Cast mut
let mut value = 5i32;
let any: &mut dyn Any = &mut value;
let v: &mut dyn AddAssign<i32> = any.cast().unwrap();
*v += 3;
assert_eq!(value, 5 + 3);
// Cast Box
let any: Box<dyn Any> = Box::new(0i32);
let _: Box<dyn Debug> = any.cast().unwrap();
// Cast Rc
use std::rc::Rc;
let any: Rc<dyn Any> = Rc::new(0i32);
let _: Rc<dyn Debug> = any.cast().unwrap();
// Cast Arc
use std::sync::Arc;
let any: Arc<dyn Any + Sync + Send> = Arc::new(0i32);
let _: Arc<dyn Debug> = any.cast().unwrap();
// Explicit registry usage
let any: &dyn Any = &0i32;
let _: &dyn Debug = REGISTRY.cast_ref(any).unwrap();
// Custom non-static registry
let myreg = Registry::new(&[entry!(i32 => dyn Debug)]);
let _: &dyn Debug = myreg.cast_ref(any).unwrap();
// Autotraits and type/const generics are distinct
let a: Option<&(dyn Debug + Sync)> = any.cast();
assert!(a.is_none());
// Registration in the default registry can happen anywhere
// in any order in any downstream crate
register! { i32 => dyn AddAssign<i32> }
相关软件包
intertrait
:crosstrait
的想法来源,类似目标,类似功能,std
,proc macrosminiconf
: 提供了从异构嵌套数据结构中的节点获取dyn Any
的多种方法,no_std
,no allocerased_serde
:Serialize/
Serializer/
Deserializer
特性对象downcast
/downcast-rs
: 支持dyn Trait -> 类型
linkme
: 用于构建分布式静态类型注册表的链接器魔法
限制
no_std
上的注册表大小
目前 no_std
上全局注册表的大小是固定的,并任意设置为 128 个条目。
自动特性
由于将任何组合的自定义特性(特别是 Send
、Sync
、Unpin
)添加到特质会导致生成一个独特的特质,因此所有相关的特质组合加上自定义特性都需要显式注册。
全局注册表
可以显式构建和使用自定义的非静态 Registry
,但 Cast
特性将不会使用它。
used_linker
可能需要不稳定的 used_with_arg
功能来防止链接器优化掉注册表中的项目。通过使用 used_linker
crate 功能并使用夜间工具链来启用它。
注册表键
注册表键的大小为 size_of::<[TypeId; 2]>() = 32
字节。哈希和键存储/比较没有针对性能进行调整。
依赖关系
~2.5MB
~47K SLoC