mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-21 08:46:35 +00:00
@ -21,7 +21,7 @@ ifeq ($(ARCH), x86_64)
|
||||
endif
|
||||
endif
|
||||
|
||||
RUSTFLAGS = $(RUSTFLAGS_UNWIND)
|
||||
RUSTFLAGS += $(RUSTFLAGS_UNWIND)
|
||||
|
||||
CFLAGS = $(GLOBAL_CFLAGS) -fno-pie $(CFLAGS_UNWIND) -I $(shell pwd) -I $(shell pwd)/include
|
||||
|
||||
@ -40,7 +40,7 @@ kernel_subdirs := common driver debug syscall libs
|
||||
|
||||
|
||||
kernel_rust:
|
||||
RUSTFLAGS="$(RUSTFLAGS)" cargo +nightly-2023-08-15 $(CARGO_ZBUILD) build --release --target $(TARGET_JSON)
|
||||
RUSTFLAGS="$(RUSTFLAGS)" cargo +nightly-2024-07-23 $(CARGO_ZBUILD) build --release --target $(TARGET_JSON)
|
||||
|
||||
|
||||
all: kernel
|
||||
|
@ -1,4 +1,5 @@
|
||||
/// 每个架构都需要实现的IO接口
|
||||
#[allow(unused)]
|
||||
pub trait PortIOArch {
|
||||
unsafe fn in8(port: u16) -> u8;
|
||||
unsafe fn in16(port: u16) -> u16;
|
||||
|
@ -156,6 +156,7 @@ impl LocalApicTimerIntrController {
|
||||
local_apic_timer.start_current();
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(super) fn disable(&self) {
|
||||
let cpu_id = smp_get_processor_id();
|
||||
let local_apic_timer = local_apic_timer_instance_mut(cpu_id);
|
||||
|
@ -179,6 +179,7 @@ bitflags! {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(super) fn irq_msi_compose_msg(cfg: &HardwareIrqConfig, msg: &mut MsiMsg, dmar: bool) {
|
||||
*msg = MsiMsg::new_zeroed();
|
||||
|
||||
|
@ -35,6 +35,7 @@ extern "C" {
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[allow(static_mut_refs)]
|
||||
unsafe extern "C" fn kernel_main(
|
||||
mb2_info: u64,
|
||||
mb2_magic: u64,
|
||||
@ -66,6 +67,7 @@ unsafe extern "C" fn kernel_main(
|
||||
|
||||
/// 在内存管理初始化之前的架构相关的早期初始化
|
||||
#[inline(never)]
|
||||
#[allow(static_mut_refs)]
|
||||
pub fn early_setup_arch() -> Result<(), SystemError> {
|
||||
let stack_start = unsafe { *(head_stack_start as *const u64) } as usize;
|
||||
debug!("head_stack_start={:#x}\n", stack_start);
|
||||
|
@ -564,6 +564,7 @@ pub unsafe fn set_system_trap_gate(irq: u32, ist: u8, vaddr: VirtAddr) {
|
||||
set_gate(idt_entry, 0xEF, ist, vaddr);
|
||||
}
|
||||
|
||||
#[allow(static_mut_refs)]
|
||||
unsafe fn get_idt_entry(irq: u32) -> &'static mut [u64] {
|
||||
assert!(irq < 256);
|
||||
let mut idt_vaddr =
|
||||
|
@ -26,6 +26,7 @@ pub struct X86MsiDataNormal {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub struct X86MsiDataDmar {
|
||||
pub dmar_subhandle: u32,
|
||||
}
|
||||
|
@ -396,6 +396,7 @@ impl SigContext {
|
||||
}
|
||||
}
|
||||
/// @brief 信号处理备用栈的信息
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct SigStack {
|
||||
pub sp: *mut c_void,
|
||||
|
@ -42,6 +42,7 @@ pub struct MSRBitmap {
|
||||
pub data: [u8; PAGE_SIZE],
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub struct VcpuData {
|
||||
/// The virtual and physical address of the Vmxon naturally aligned 4-KByte region of memory
|
||||
@ -73,6 +74,7 @@ pub enum VcpuState {
|
||||
Act = 2,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub struct VmxVcpu {
|
||||
pub vcpu_id: u32,
|
||||
@ -318,13 +320,13 @@ impl VmxVcpu {
|
||||
)?;
|
||||
vmx_vmwrite(
|
||||
VmcsFields::HOST_GDTR_BASE as u32,
|
||||
pseudo_descriptpr.base.to_bits() as u64,
|
||||
pseudo_descriptpr.base as usize as u64,
|
||||
)?;
|
||||
vmx_vmwrite(VmcsFields::HOST_IDTR_BASE as u32, unsafe {
|
||||
let mut pseudo_descriptpr: x86::dtables::DescriptorTablePointer<u64> =
|
||||
Default::default();
|
||||
x86::dtables::sidt(&mut pseudo_descriptpr);
|
||||
pseudo_descriptpr.base.to_bits() as u64
|
||||
pseudo_descriptpr.base as usize as u64
|
||||
})?;
|
||||
|
||||
// fast entry into the kernel
|
||||
|
@ -64,10 +64,10 @@ pub fn vmx_vmlaunch() -> Result<(), SystemError> {
|
||||
"push rsi",
|
||||
"push rdi",
|
||||
"vmwrite {0:r}, rsp",
|
||||
"lea rax, 1f[rip]",
|
||||
"lea rax, 2f[rip]",
|
||||
"vmwrite {1:r}, rax",
|
||||
"vmlaunch",
|
||||
"1:",
|
||||
"2:",
|
||||
"pop rdi",
|
||||
"pop rsi",
|
||||
"pop rdx",
|
||||
|
@ -30,6 +30,7 @@ pub use interrupt::X86_64InterruptArch as CurrentIrqArch;
|
||||
pub use crate::arch::asm::pio::X86_64PortIOArch as CurrentPortIOArch;
|
||||
pub use kvm::X86_64KVMArch as KVMArch;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
pub use crate::arch::ipc::signal::X86_64SignalArch as CurrentSignalArch;
|
||||
pub use crate::arch::time::X86_64TimeArch as CurrentTimeArch;
|
||||
|
||||
|
@ -42,9 +42,8 @@ impl KernelThreadMechanism {
|
||||
frame.rip = kernel_thread_bootstrap_stage1 as usize as u64;
|
||||
|
||||
// fork失败的话,子线程不会执行。否则将导致内存安全问题。
|
||||
let pid = ProcessManager::fork(&frame, clone_flags).map_err(|e| {
|
||||
let pid = ProcessManager::fork(&frame, clone_flags).inspect_err(|_e| {
|
||||
unsafe { KernelThreadCreateInfo::parse_unsafe_arc_ptr(create_info) };
|
||||
e
|
||||
})?;
|
||||
|
||||
ProcessManager::find(pid)
|
||||
|
@ -59,6 +59,7 @@ impl TSSManager {
|
||||
x86::task::load_tr(selector);
|
||||
}
|
||||
|
||||
#[allow(static_mut_refs)]
|
||||
unsafe fn set_tss_descriptor(index: u16, vaddr: VirtAddr) {
|
||||
const LIMIT: u64 = 103;
|
||||
let gdt_vaddr = VirtAddr::new(&GDT_Table as *const _ as usize);
|
||||
|
@ -259,6 +259,7 @@ impl X86_64SMPArch {
|
||||
}
|
||||
|
||||
impl SmpCpuManager {
|
||||
#[allow(static_mut_refs)]
|
||||
pub fn arch_init(_boot_cpu: ProcessorId) {
|
||||
assert!(smp_get_processor_id().data() == 0);
|
||||
// 写入APU_START_CR3,这个值会在AP处理器启动时设置到CR3寄存器
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"llvm-target": "x86_64-unknown-none",
|
||||
"data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128",
|
||||
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
|
||||
"arch": "x86_64",
|
||||
"target-endian": "little",
|
||||
"target-pointer-width": "64",
|
||||
|
@ -111,6 +111,7 @@ impl Bus for AcpiBus {
|
||||
///
|
||||
///
|
||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/acpi/acpi_bus.h#364
|
||||
#[allow(unused)]
|
||||
pub trait AcpiDevice: Device {}
|
||||
|
||||
/// Acpi驱动应当实现的trait
|
||||
@ -120,4 +121,5 @@ pub trait AcpiDevice: Device {}
|
||||
/// todo: 仿照linux的acpi_driver去设计这个trait
|
||||
///
|
||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/acpi/acpi_bus.h#163
|
||||
#[allow(unused)]
|
||||
pub trait AcpiDriver: Driver {}
|
||||
|
@ -478,9 +478,8 @@ impl BusManager {
|
||||
|
||||
driver_manager()
|
||||
.create_attr_file(driver, &DriverAttrBind)
|
||||
.map_err(|e| {
|
||||
.inspect_err(|_e| {
|
||||
driver_manager().remove_attr_file(driver, &DriverAttrUnbind);
|
||||
e
|
||||
})?;
|
||||
|
||||
return Ok(());
|
||||
|
@ -142,6 +142,7 @@ impl DeviceManager {
|
||||
/// - Ok(true): 匹配成功
|
||||
/// - Ok(false): 没有匹配成功
|
||||
/// - Err(SystemError): 匹配过程中出现意外错误,没有匹配成功
|
||||
///
|
||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/base/dd.c#899
|
||||
fn do_device_attach_driver(
|
||||
&self,
|
||||
@ -484,17 +485,15 @@ impl DriverManager {
|
||||
|
||||
sysfs_instance()
|
||||
.create_link(Some(&device_kobj), &driver_kobj, "driver".to_string())
|
||||
.map_err(|e| {
|
||||
.inspect_err(|_e| {
|
||||
fail_rm_dev_link();
|
||||
e
|
||||
})?;
|
||||
|
||||
device_manager()
|
||||
.create_file(device, &DeviceAttrCoredump)
|
||||
.map_err(|e| {
|
||||
.inspect_err(|_e| {
|
||||
sysfs_instance().remove_link(&device_kobj, "driver".to_string());
|
||||
fail_rm_dev_link();
|
||||
e
|
||||
})?;
|
||||
|
||||
return Ok(());
|
||||
|
@ -213,10 +213,10 @@ impl DriverManager {
|
||||
|
||||
bus_manager().add_driver(&driver)?;
|
||||
|
||||
self.add_groups(&driver, driver.groups()).map_err(|e| {
|
||||
bus_manager().remove_driver(&driver);
|
||||
e
|
||||
})?;
|
||||
self.add_groups(&driver, driver.groups())
|
||||
.inspect_err(|_e| {
|
||||
bus_manager().remove_driver(&driver);
|
||||
})?;
|
||||
|
||||
// todo: 发送uevent
|
||||
|
||||
|
@ -646,18 +646,16 @@ impl DeviceManager {
|
||||
let parent_kobj = parent.clone() as Arc<dyn KObject>;
|
||||
sysfs_instance()
|
||||
.create_link(Some(&dev_kobj), &parent_kobj, "device".to_string())
|
||||
.map_err(|e| {
|
||||
.inspect_err(|_e| {
|
||||
err_remove_subsystem(&dev_kobj);
|
||||
e
|
||||
})?;
|
||||
}
|
||||
|
||||
sysfs_instance()
|
||||
.create_link(Some(&subsys_kobj), &dev_kobj, dev.name())
|
||||
.map_err(|e| {
|
||||
.inspect_err(|_e| {
|
||||
err_remove_device(&dev_kobj);
|
||||
err_remove_subsystem(&dev_kobj);
|
||||
e
|
||||
})?;
|
||||
|
||||
return Ok(());
|
||||
@ -695,18 +693,16 @@ impl DeviceManager {
|
||||
// 添加kobj_type的属性文件
|
||||
if let Some(kobj_type) = dev.kobj_type() {
|
||||
self.add_groups(dev, kobj_type.attribute_groups().unwrap_or(&[]))
|
||||
.map_err(|e| {
|
||||
.inspect_err(|_e| {
|
||||
err_remove_class_groups(dev);
|
||||
e
|
||||
})?;
|
||||
}
|
||||
|
||||
// 添加设备本身的属性文件
|
||||
self.add_groups(dev, dev.attribute_groups().unwrap_or(&[]))
|
||||
.map_err(|e| {
|
||||
.inspect_err(|_e| {
|
||||
err_remove_kobj_type_groups(dev);
|
||||
err_remove_class_groups(dev);
|
||||
e
|
||||
})?;
|
||||
|
||||
return Ok(());
|
||||
|
@ -64,6 +64,7 @@ pub trait PlatformDevice: Device {
|
||||
/// @brief: 判断设备是否初始化
|
||||
/// @parameter: None
|
||||
/// @return: 如果已经初始化,返回true,否则,返回false
|
||||
#[allow(dead_code)]
|
||||
fn is_initialized(&self) -> bool;
|
||||
|
||||
/// @brief: 设置设备状态
|
||||
|
@ -16,6 +16,7 @@ use super::{platform_bus, platform_device::PlatformDevice};
|
||||
///
|
||||
/// 应当在所有实现这个trait的结构体上方,添加 `#[cast_to([sync] PlatformDriver)]`,
|
||||
/// 否则运行时将报错“该对象不是PlatformDriver”
|
||||
#[allow(dead_code)]
|
||||
pub trait PlatformDriver: Driver {
|
||||
/// 检测设备是否能绑定到这个驱动
|
||||
///
|
||||
|
@ -16,6 +16,7 @@ static mut CMAPPER: Option<LockedCacheMapper> = None;
|
||||
/// 该结构体向外提供BlockCache服务
|
||||
pub struct BlockCache;
|
||||
|
||||
#[allow(static_mut_refs)]
|
||||
unsafe fn mapper() -> Result<&'static mut LockedCacheMapper, BlockCacheError> {
|
||||
unsafe {
|
||||
match &mut CMAPPER {
|
||||
@ -25,6 +26,7 @@ unsafe fn mapper() -> Result<&'static mut LockedCacheMapper, BlockCacheError> {
|
||||
};
|
||||
}
|
||||
|
||||
#[allow(static_mut_refs)]
|
||||
unsafe fn space() -> Result<&'static mut LockedCacheSpace, BlockCacheError> {
|
||||
unsafe {
|
||||
match &mut CSPACE {
|
||||
|
@ -195,9 +195,8 @@ impl AhciDisk {
|
||||
return Err(SystemError::EIO);
|
||||
}
|
||||
}
|
||||
|
||||
if kbuf.is_some() {
|
||||
buf.copy_from_slice(kbuf.as_ref().unwrap());
|
||||
if let Some(kbuf) = &kbuf {
|
||||
buf.copy_from_slice(kbuf);
|
||||
}
|
||||
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
@ -43,6 +43,7 @@ pub enum HbaPortType {
|
||||
|
||||
/// 声明了 HBA 的所有属性
|
||||
#[repr(packed)]
|
||||
#[allow(dead_code)]
|
||||
pub struct HbaPort {
|
||||
pub clb: u64, // 0x00, command list base address, 1K-byte aligned
|
||||
pub fb: u64, // 0x08, FIS base address, 256-byte aligned
|
||||
@ -65,6 +66,7 @@ pub struct HbaPort {
|
||||
|
||||
/// 全称 HBA Memory Register,是HBA的寄存器在内存中的映射
|
||||
#[repr(packed)]
|
||||
#[allow(dead_code)]
|
||||
pub struct HbaMem {
|
||||
pub cap: u32, // 0x00, Host capability
|
||||
pub ghc: u32, // 0x04, Global host control
|
||||
@ -94,6 +96,7 @@ pub struct HbaPrdtEntry {
|
||||
/// HAB Command Table
|
||||
/// 每个 Port 一个 Table,主机和设备的交互都靠这个数据结构
|
||||
#[repr(packed)]
|
||||
#[allow(dead_code)]
|
||||
pub struct HbaCmdTable {
|
||||
// 0x00
|
||||
pub cfis: [u8; 64], // Command FIS
|
||||
@ -262,6 +265,7 @@ pub enum FisType {
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
#[allow(dead_code)]
|
||||
pub struct FisRegH2D {
|
||||
// DWORD 0
|
||||
pub fis_type: u8, // FIS_TYPE_REG_H2D
|
||||
|
@ -168,9 +168,8 @@ fn uefi_init(system_table: PhysAddr) -> Result<(), SystemError> {
|
||||
let st_ptr = st_vaddr.data() as *const uefi_raw::table::system::SystemTable;
|
||||
efi_manager()
|
||||
.check_system_table_header(unsafe { &st_ptr.as_ref().unwrap().header }, 2)
|
||||
.map_err(|e| {
|
||||
.inspect_err(|_| {
|
||||
err_unmap_systable(st_vaddr);
|
||||
e
|
||||
})?;
|
||||
|
||||
let st_ref = unsafe { st_ptr.as_ref().unwrap() };
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::driver::{base::device::Device, input::serio::serio_device::SerioDevice};
|
||||
|
||||
// todo: https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/libps2.h#33
|
||||
#[allow(unused)]
|
||||
pub trait Ps2Device: Device + SerioDevice {}
|
||||
|
@ -387,6 +387,7 @@ impl Ps2MouseDevice {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn wait_for_read(&self) -> Result<(), SystemError> {
|
||||
let timeout = 100_000;
|
||||
for _ in 0..timeout {
|
||||
|
@ -47,14 +47,16 @@ pub fn i8042_init() -> Result<(), SystemError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// TODO: https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/input/serio/i8042.c#441
|
||||
/// TODO: https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/input/serio/i8042.c#441
|
||||
#[allow(dead_code)]
|
||||
pub fn i8042_start(_serio: &Arc<dyn SerioDevice>) -> Result<(), SystemError> {
|
||||
todo!()
|
||||
todo!("i8042_start")
|
||||
}
|
||||
|
||||
// TODO: https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/input/serio/i8042.c#471
|
||||
/// TODO: https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/input/serio/i8042.c#471
|
||||
#[allow(dead_code)]
|
||||
pub fn i8042_stop(_serio: &Arc<dyn SerioDevice>) -> Result<(), SystemError> {
|
||||
todo!()
|
||||
todo!("i8042_stop")
|
||||
}
|
||||
|
||||
/// # 函数的功能
|
||||
|
@ -8,6 +8,7 @@ use super::serio_bus;
|
||||
/// 串行设备,实现该trait的设备实例挂载在serio总线上,同时应该实现Device trait
|
||||
///
|
||||
/// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/serio.h#20
|
||||
#[allow(dead_code)]
|
||||
pub trait SerioDevice: Device {
|
||||
/// # 函数功能
|
||||
///
|
||||
|
@ -11,6 +11,7 @@ use super::{serio_bus, serio_device::SerioDevice};
|
||||
/// 实现该trait的设备驱动实例应挂载在serio总线上,同时应该实现Driver trait
|
||||
///
|
||||
/// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/serio.h#67
|
||||
#[allow(dead_code)]
|
||||
pub trait SerioDriver: Driver {
|
||||
// 写入时唤醒设备
|
||||
fn write_wakeup(&self, device: &Arc<dyn SerioDevice>) -> Result<(), SystemError>;
|
||||
|
@ -780,7 +780,8 @@ const E1000E_TXD_CMD_EOP: u8 = 1 << 0;
|
||||
const E1000E_TXD_CMD_IFCS: u8 = 1 << 1;
|
||||
const E1000E_TXD_CMD_RS: u8 = 1 << 3;
|
||||
|
||||
// E1000E驱动初始化过程中可能的错误
|
||||
/// E1000E驱动初始化过程中可能的错误
|
||||
#[allow(dead_code)]
|
||||
pub enum E1000EPciError {
|
||||
// 获取到错误类型的BAR(IO BAR)
|
||||
// An IO BAR was provided rather than a memory BAR.
|
||||
|
@ -15,7 +15,6 @@ use alloc::sync::{Arc, Weak};
|
||||
use alloc::vec::Vec;
|
||||
use core::cell::UnsafeCell;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use log::debug;
|
||||
use smoltcp::wire::HardwareAddress;
|
||||
use smoltcp::{
|
||||
phy::{self},
|
||||
|
@ -13,7 +13,7 @@ pub mod e1000e;
|
||||
pub mod irq_handle;
|
||||
pub mod loopback;
|
||||
pub mod virtio_net;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub trait NetDevice: Device {
|
||||
/// @brief 获取网卡的MAC地址
|
||||
fn mac(&self) -> EthernetAddress;
|
||||
|
@ -468,8 +468,7 @@ fn read_cell(reg_value: &[u8], base_index: usize, cells: usize) -> (u64, usize)
|
||||
1 => {
|
||||
return (
|
||||
u32::from_be_bytes(reg_value[base_index..base_index + 4].try_into().unwrap())
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
.into(),
|
||||
next_base_index,
|
||||
);
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ use super::{dev_id::PciDeviceID, device::PciDevice, subsys::pci_bus};
|
||||
/// Pci驱动应该实现的trait
|
||||
///
|
||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/pci.h#907
|
||||
#[allow(dead_code)]
|
||||
pub trait PciDriver: Driver {
|
||||
/// # 函数的功能
|
||||
/// 对设备进行probe操作
|
||||
|
@ -47,6 +47,7 @@ pub trait RtcDevice: Device {
|
||||
fn class_ops(&self) -> &'static dyn RtcClassOps;
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub trait RtcClassOps: Send + Sync + Debug {
|
||||
fn read_time(&self, dev: &Arc<dyn RtcDevice>) -> Result<RtcTime, SystemError>;
|
||||
fn set_time(&self, dev: &Arc<dyn RtcDevice>, time: &RtcTime) -> Result<(), SystemError>;
|
||||
|
@ -9,6 +9,7 @@ use self::serial8250::serial8250_manager;
|
||||
|
||||
pub mod serial8250;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub trait UartDriver: Debug + Send + Sync {
|
||||
fn device_number(&self) -> DeviceNumber;
|
||||
|
||||
@ -21,6 +22,7 @@ pub trait UartDriver: Debug + Send + Sync {
|
||||
/// 串口端口应当实现的trait
|
||||
///
|
||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/serial_core.h#428
|
||||
#[allow(dead_code)]
|
||||
pub trait UartPort {
|
||||
fn iobase(&self) -> Option<usize> {
|
||||
None
|
||||
|
@ -141,6 +141,7 @@ impl Serial8250Manager {
|
||||
}
|
||||
|
||||
/// 所有的8250串口设备都应该实现的trait
|
||||
#[allow(dead_code)]
|
||||
trait Serial8250Port: UartPort {
|
||||
fn device(&self) -> Option<Arc<Serial8250ISADevices>> {
|
||||
None
|
||||
|
@ -20,6 +20,7 @@ static mut PIO_PORTS: [Option<Serial8250PIOPort>; 8] =
|
||||
[None, None, None, None, None, None, None, None];
|
||||
|
||||
impl Serial8250Manager {
|
||||
#[allow(static_mut_refs)]
|
||||
pub(super) fn bind_pio_ports(
|
||||
&self,
|
||||
uart_driver: &Arc<Serial8250ISADriver>,
|
||||
@ -251,6 +252,7 @@ impl Serial8250PIOPortInner {
|
||||
Self { device: None }
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn device(&self) -> Option<Arc<Serial8250ISADevices>> {
|
||||
if let Some(device) = self.device.as_ref() {
|
||||
return device.upgrade();
|
||||
|
@ -10,6 +10,7 @@ pub trait ConsoleSwitch: Sync + Send {
|
||||
fn con_init(&self, vc_data: &mut VirtualConsoleData, init: bool) -> Result<(), SystemError>;
|
||||
|
||||
/// 进行释放等系列操作,目前未使用
|
||||
#[allow(dead_code)]
|
||||
fn con_deinit(&self) -> Result<(), SystemError>;
|
||||
|
||||
/// ## 清空console的一片区域
|
||||
|
@ -7,7 +7,6 @@ use alloc::{
|
||||
collections::LinkedList,
|
||||
string::String,
|
||||
sync::{Arc, Weak},
|
||||
vec::Vec,
|
||||
};
|
||||
use system_error::SystemError;
|
||||
|
||||
@ -277,14 +276,6 @@ pub struct TtyContorlInfo {
|
||||
pub packet: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct TtyCoreWriteData {
|
||||
/// 写缓冲区
|
||||
pub write_buf: Vec<u8>,
|
||||
/// 写入数量
|
||||
pub write_cnt: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct TtyFlowState {
|
||||
/// 表示流控是否被停止
|
||||
@ -465,9 +456,6 @@ impl TtyCoreData {
|
||||
}
|
||||
}
|
||||
|
||||
/// TTY 核心接口,不同的tty需要各自实现这个trait
|
||||
pub trait TtyCoreFuncs: Debug + Send + Sync {}
|
||||
|
||||
impl TtyOperation for TtyCore {
|
||||
#[inline]
|
||||
fn open(&self, tty: &TtyCoreData) -> Result<(), SystemError> {
|
||||
|
@ -1344,7 +1344,7 @@ impl NTtyData {
|
||||
tty.write(core, &[8], 1)?;
|
||||
}
|
||||
if tty.put_char(tty.core(), b' ').is_err() {
|
||||
tty.write(core, &[b' '], 1)?;
|
||||
tty.write(core, b" ", 1)?;
|
||||
}
|
||||
self.cursor_column -= 1;
|
||||
space -= 1;
|
||||
@ -1357,7 +1357,7 @@ impl NTtyData {
|
||||
}
|
||||
|
||||
if tty.put_char(tty.core(), b'^').is_err() {
|
||||
tty.write(core, &[b'^'], 1)?;
|
||||
tty.write(core, b"^", 1)?;
|
||||
}
|
||||
|
||||
if tty.put_char(tty.core(), ch ^ 0o100).is_err() {
|
||||
|
@ -132,7 +132,6 @@ pub struct VirtualConsoleData {
|
||||
pub utf_char: u32,
|
||||
/// 构建utf时需要的参数,表示目前接收了多少个字节的数据来构建utf字符
|
||||
pub npar: u32,
|
||||
///
|
||||
pub par: [u32; NPAR],
|
||||
|
||||
/// 字符转换表 用于将输入字符映射到特定的字符
|
||||
@ -1786,6 +1785,7 @@ impl VirtualConsoleData {
|
||||
draw.size = 0;
|
||||
}
|
||||
|
||||
#[allow(clippy::manual_rotate)]
|
||||
fn build_attr(
|
||||
&self,
|
||||
color: u8,
|
||||
|
@ -341,12 +341,12 @@ impl Attribute for AttrCursorBlink {
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
#[allow(dead_code)]
|
||||
pub struct FrameBufferConsoleData {
|
||||
/// 光标闪烁间隔
|
||||
pub cursor_blink_jiffies: i64,
|
||||
/// 是否刷新光标
|
||||
pub cursor_flash: bool,
|
||||
///
|
||||
pub display: FbConsoleDisplay,
|
||||
/// 光标状态
|
||||
pub cursor_state: FbCursor,
|
||||
|
@ -301,6 +301,7 @@ impl FrameBufferInfoData {
|
||||
}
|
||||
|
||||
/// 帧缓冲区信息
|
||||
#[allow(dead_code)]
|
||||
pub trait FrameBufferInfo: FrameBufferOps {
|
||||
fn framebuffer_info_data(&self) -> &RwLock<FrameBufferInfoData>;
|
||||
|
||||
@ -377,6 +378,7 @@ pub trait FrameBufferInfo: FrameBufferOps {
|
||||
/// 帧缓冲区操作
|
||||
///
|
||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/fb.h#237
|
||||
#[allow(dead_code)]
|
||||
pub trait FrameBufferOps {
|
||||
fn fb_open(&self, user: bool);
|
||||
fn fb_release(&self, user: bool);
|
||||
@ -1063,6 +1065,7 @@ pub enum FbAccel {
|
||||
// Add other accelerators here
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct BootTimeScreenInfo {
|
||||
pub origin_x: u8,
|
||||
|
@ -18,6 +18,7 @@ pub mod virtio_impl;
|
||||
/// virtio 设备厂商ID
|
||||
pub const VIRTIO_VENDOR_ID: u16 = 0x1af4;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub trait VirtIODevice: Device {
|
||||
fn handle_irq(&self, _irq: IrqNumber) -> Result<IrqReturn, SystemError>;
|
||||
|
||||
|
@ -35,6 +35,7 @@ use super::{
|
||||
};
|
||||
|
||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#506
|
||||
#[allow(dead_code)]
|
||||
pub trait IrqChip: Sync + Send + Any + Debug {
|
||||
fn name(&self) -> &'static str;
|
||||
/// start up the interrupt (defaults to ->enable if ENOSYS)
|
||||
@ -127,6 +128,7 @@ pub trait IrqChip: Sync + Send + Any + Debug {
|
||||
}
|
||||
|
||||
/// enable/disable power management wake-on of an interrupt
|
||||
#[allow(dead_code)]
|
||||
fn irq_set_wake(&self, _irq_data: &Arc<IrqData>, _on: bool) -> Result<(), SystemError> {
|
||||
Err(SystemError::ENOSYS)
|
||||
}
|
||||
@ -281,6 +283,7 @@ struct InnerIrqChipGeneric {
|
||||
chip_types: Vec<IrqChipType>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub trait IrqChipGenericOps: Debug + Send + Sync {
|
||||
/// Alternate I/O accessor (defaults to readl if NULL)
|
||||
unsafe fn reg_readl(&self, addr: VirtAddr) -> u32;
|
||||
|
@ -644,6 +644,7 @@ pub enum IrqDomainBusToken {
|
||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#107
|
||||
pub trait IrqDomainOps: Debug + Send + Sync {
|
||||
/// 匹配一个中断控制器设备节点到一个主机。
|
||||
#[allow(dead_code)]
|
||||
fn match_node(
|
||||
&self,
|
||||
_irq_domain: &Arc<IrqDomain>,
|
||||
@ -667,6 +668,7 @@ pub trait IrqDomainOps: Debug + Send + Sync {
|
||||
}
|
||||
|
||||
/// 删除一个虚拟中断号与一个硬件中断号之间的映射。
|
||||
#[allow(dead_code)]
|
||||
fn unmap(&self, irq_domain: &Arc<IrqDomain>, virq: IrqNumber);
|
||||
|
||||
fn activate(
|
||||
|
@ -124,6 +124,7 @@ impl MsiDesc {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub trait MsiDescFunc: Debug + Send + Sync {
|
||||
/// Callback that may be called when the MSI message
|
||||
/// address or data changes.
|
||||
|
@ -1328,6 +1328,7 @@ impl ShortDirEntry {
|
||||
}
|
||||
|
||||
/// @brief 计算短目录项的名称的校验和
|
||||
#[allow(clippy::manual_rotate)]
|
||||
fn checksum(&self) -> u8 {
|
||||
let mut result = 0;
|
||||
|
||||
|
@ -45,6 +45,7 @@ pub const MAX_FILE_SIZE: u64 = 0xffff_ffff;
|
||||
|
||||
/// @brief 表示当前簇和上一个簇的关系的结构体
|
||||
/// 定义这样一个结构体的原因是,FAT文件系统的文件中,前后两个簇具有关联关系。
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct Cluster {
|
||||
pub cluster_num: u64,
|
||||
@ -642,7 +643,7 @@ impl FATFileSystem {
|
||||
self.set_entry(cluster, FATEntry::Unused)?;
|
||||
self.fs_info.0.lock().update_free_count_delta(1);
|
||||
// 安全选项:清空被释放的簇
|
||||
#[cfg(feature = "secure")]
|
||||
#[cfg(feature = "fatfs-secure")]
|
||||
self.zero_cluster(cluster)?;
|
||||
return Ok(());
|
||||
} else {
|
||||
|
@ -55,7 +55,7 @@ impl MbrDiskPartitionTableEntry {
|
||||
#[repr(packed)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct MbrDiskPartionTable {
|
||||
pub reserved: [u8; 446],
|
||||
pub _reserved: [u8; 446],
|
||||
pub dpte: [MbrDiskPartitionTableEntry; 4], // 磁盘分区表项
|
||||
pub bs_trailsig: u16,
|
||||
}
|
||||
@ -63,7 +63,7 @@ pub struct MbrDiskPartionTable {
|
||||
impl Default for MbrDiskPartionTable {
|
||||
fn default() -> Self {
|
||||
MbrDiskPartionTable {
|
||||
reserved: [0; 446],
|
||||
_reserved: [0; 446],
|
||||
dpte: [Default::default(); 4],
|
||||
bs_trailsig: Default::default(),
|
||||
}
|
||||
|
@ -1,5 +1,3 @@
|
||||
use core::usize;
|
||||
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::syscall::Syscall;
|
||||
|
@ -25,6 +25,9 @@ use super::vfs::{
|
||||
file::FilePrivateData, syscall::ModeType, utils::DName, FileSystem, FileSystemMaker, FsInfo,
|
||||
IndexNode, InodeId, Metadata, SpecialNodeData,
|
||||
};
|
||||
|
||||
use linkme::distributed_slice;
|
||||
|
||||
use super::vfs::{Magic, SuperBlock};
|
||||
|
||||
/// RamFS的inode名称的最大长度
|
||||
|
@ -136,9 +136,8 @@ impl SysFS {
|
||||
if let Some(name) = group.name() {
|
||||
parent_inode = inode
|
||||
.find(name)
|
||||
.map_err(|e| {
|
||||
.inspect_err(|_e| {
|
||||
warn!("sysfs group '{name}' not found for kobject {kobj:?}");
|
||||
e
|
||||
})?
|
||||
.downcast_arc()
|
||||
.unwrap();
|
||||
|
@ -160,25 +160,6 @@ impl MountFSInode {
|
||||
}
|
||||
}
|
||||
|
||||
/// 将新的挂载点-挂载文件系统添加到父级的挂载树
|
||||
pub(super) fn do_mount(
|
||||
&self,
|
||||
inode_id: InodeId,
|
||||
new_mount_fs: Arc<MountFS>,
|
||||
) -> Result<(), SystemError> {
|
||||
let mut guard = self.mount_fs.mountpoints.lock();
|
||||
if guard.contains_key(&inode_id) {
|
||||
return Err(SystemError::EBUSY);
|
||||
}
|
||||
guard.insert(inode_id, new_mount_fs);
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
pub(super) fn inode_id(&self) -> InodeId {
|
||||
self.metadata().map(|x| x.inode_id).unwrap()
|
||||
}
|
||||
|
||||
fn do_find(&self, name: &str) -> Result<Arc<MountFSInode>, SystemError> {
|
||||
// 直接调用当前inode所在的文件系统的find方法进行查找
|
||||
// 由于向下查找可能会跨越文件系统的边界,因此需要尝试替换inode
|
||||
|
@ -398,6 +398,7 @@ impl PosixOpenHow {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct OpenHow {
|
||||
pub o_flags: FileMode,
|
||||
@ -1707,8 +1708,7 @@ impl IoVecs {
|
||||
// 将用户空间的IoVec转换为引用(注意:这里的引用是静态的,因为用户空间的IoVec不会被释放)
|
||||
let iovs: &[IoVec] = core::slice::from_raw_parts(iov, iovcnt);
|
||||
|
||||
let mut slices: Vec<&mut [u8]> = vec![];
|
||||
slices.reserve(iovs.len());
|
||||
let mut slices: Vec<&mut [u8]> = Vec::with_capacity(iovs.len());
|
||||
|
||||
for iov in iovs.iter() {
|
||||
if iov.iov_len == 0 {
|
||||
|
@ -1,8 +1,7 @@
|
||||
use core::cmp::Ordering;
|
||||
use core::fmt::Debug;
|
||||
use core::fmt::{self, Debug};
|
||||
use core::hash::Hash;
|
||||
|
||||
use alloc::string::ToString;
|
||||
use alloc::{string::String, sync::Arc};
|
||||
use system_error::SystemError;
|
||||
|
||||
@ -135,9 +134,9 @@ impl Clone for DName {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for DName {
|
||||
fn to_string(&self) -> String {
|
||||
(*self.0).clone()
|
||||
impl fmt::Display for DName {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ fn init_intertrait() {
|
||||
#[derive(Debug)]
|
||||
pub struct BootParams {
|
||||
pub screen_info: BootTimeScreenInfo,
|
||||
#[allow(dead_code)]
|
||||
pub arch: ArchBootParams,
|
||||
boot_command_line: [u8; Self::BOOT_COMMAND_LINE_SIZE],
|
||||
}
|
||||
|
@ -64,6 +64,7 @@ pub struct SignalStruct {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub struct InnerSignalStruct {
|
||||
pub cnt: AtomicI64,
|
||||
/// 如果对应linux,这部分会有一个引用计数,但是没发现在哪里有用到需要计算引用的地方,因此
|
||||
|
@ -7,22 +7,20 @@
|
||||
#![feature(const_for)]
|
||||
#![feature(const_mut_refs)]
|
||||
#![feature(const_trait_impl)]
|
||||
#![feature(const_transmute_copy)]
|
||||
#![feature(const_refs_to_cell)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(c_void_variant)]
|
||||
#![feature(extract_if)]
|
||||
#![feature(fn_align)]
|
||||
#![feature(inline_const)]
|
||||
#![feature(naked_functions)]
|
||||
#![feature(new_uninit)]
|
||||
#![feature(panic_info_message)]
|
||||
#![feature(ptr_internals)]
|
||||
#![feature(ptr_to_from_bits)]
|
||||
#![feature(trait_upcasting)]
|
||||
#![feature(slice_ptr_get)]
|
||||
#![feature(sync_unsafe_cell)]
|
||||
#![feature(vec_into_raw_parts)]
|
||||
#![cfg_attr(target_os = "none", no_std)]
|
||||
#![allow(internal_features)]
|
||||
// clippy的配置
|
||||
#![deny(clippy::all)]
|
||||
#![allow(clippy::bad_bit_mask)]
|
||||
@ -123,15 +121,7 @@ pub fn panic(info: &PanicInfo) -> ! {
|
||||
println!("No location info");
|
||||
}
|
||||
}
|
||||
|
||||
match info.message() {
|
||||
Some(msg) => {
|
||||
println!("Message:\n\t{}", msg);
|
||||
}
|
||||
None => {
|
||||
println!("No panic message.");
|
||||
}
|
||||
}
|
||||
println!("Message:\n\t{}", info.message());
|
||||
|
||||
#[cfg(all(feature = "backtrace", target_arch = "x86_64"))]
|
||||
{
|
||||
|
@ -1,15 +0,0 @@
|
||||
/// @brief 由bindgen生成的结构体转换成rust原生定义的结构体的特性
|
||||
pub trait FFIBind2Rust<T> {
|
||||
/// 转换为不可变引用
|
||||
fn convert_ref(src: *const T) -> Option<&'static Self>;
|
||||
/// 转换为可变引用
|
||||
fn convert_mut(src: *mut T) -> Option<&'static mut Self>;
|
||||
}
|
||||
|
||||
pub fn __convert_mut<'a, S, D>(src: *mut S) -> Option<&'a mut D> {
|
||||
return unsafe { core::mem::transmute::<*mut S, *mut D>(src).as_mut() };
|
||||
}
|
||||
|
||||
pub fn __convert_ref<'a, S, D>(src: *const S) -> Option<&'a D> {
|
||||
return unsafe { core::mem::transmute::<*const S, *const D>(src).as_ref() };
|
||||
}
|
@ -2,6 +2,7 @@ use self::font_type::vga8x16::FONT_VGA_8X16;
|
||||
|
||||
pub mod font_type;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct FontDesc {
|
||||
pub index: usize,
|
||||
pub name: &'static str,
|
||||
|
@ -1,5 +1,6 @@
|
||||
#![no_std]
|
||||
#![feature(core_intrinsics)]
|
||||
#![allow(internal_features)]
|
||||
#![allow(clippy::needless_return)]
|
||||
|
||||
use core::intrinsics::unlikely;
|
||||
|
18
kernel/src/libs/intertrait/.gitignore
vendored
18
kernel/src/libs/intertrait/.gitignore
vendored
@ -1,18 +0,0 @@
|
||||
# Cargo lock in subs
|
||||
**/Cargo.lock
|
||||
|
||||
# Generated by Cargo
|
||||
**/target/
|
||||
|
||||
**/*.rs.bk
|
||||
**/*.iml
|
||||
.idea/
|
||||
.vscode/
|
||||
/db/
|
||||
/snapshot/
|
||||
/log/
|
||||
/keys/
|
||||
/test/log/
|
||||
|
||||
# macOS
|
||||
.DS_store
|
@ -1,27 +0,0 @@
|
||||
[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"
|
||||
|
@ -1,17 +0,0 @@
|
||||
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.
|
@ -1,163 +0,0 @@
|
||||
# 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)
|
||||
|
@ -1,23 +0,0 @@
|
||||
[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"
|
@ -1,176 +0,0 @@
|
||||
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
|
@ -1,17 +0,0 @@
|
||||
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.
|
@ -1,76 +0,0 @@
|
||||
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()?,
|
||||
})
|
||||
}
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
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]) }
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
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
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
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
|
||||
}
|
||||
}
|
@ -1,145 +0,0 @@
|
||||
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()
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
//! `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::*;
|
@ -1,45 +0,0 @@
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
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()
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
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>>()))
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
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);
|
||||
}
|
||||
}
|
@ -1,587 +0,0 @@
|
||||
//! 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) };
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "none"))]
|
||||
pub fn init_caster_map() {}
|
||||
|
||||
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>());
|
||||
}
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
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();
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
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();
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
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();
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
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);
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
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");
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
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"
|
||||
);
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
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();
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
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();
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
#[test]
|
||||
fn tests() {
|
||||
let t = trybuild::TestCases::new();
|
||||
t.compile_fail("tests/ui/*.rs");
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
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();
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
error: Duplicated flag: sync
|
||||
--> $DIR/duplicate-flags.rs:5:18
|
||||
|
|
||||
5 | #[cast_to([sync, sync] Greet)]
|
||||
| ^^^^
|
@ -1,31 +0,0 @@
|
||||
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();
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
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> {
|
||||
| ^^^^^^^^^^^^
|
@ -1,14 +0,0 @@
|
||||
use intertrait::*;
|
||||
|
||||
struct Data;
|
||||
|
||||
#[cast_to]
|
||||
impl Data {
|
||||
fn hello() {
|
||||
println!("hello!");
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _ = Data;
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
error: #[cast_to] should only be on an impl of a trait
|
||||
--> $DIR/on-type-impl.rs:6:6
|
||||
|
|
||||
6 | impl Data {
|
||||
| ^^^^
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user