gpt4 book ai didi

rust - 如何强制联合表现得好像只有一种类型?

转载 作者:行者123 更新时间:2023-11-29 08:06:09 26 4
gpt4 key购买 nike

我正在尝试为 epoll Linux API 编写一个包装器。我 fork 了this存储库,但这个 crate 不使用 epoll API 使用的 union 类型。我决定使用 Rust 的 C 联合功能来创建一个完整的包装器,用户将不需要使用不安全的代码。

这个联盟给我带来了一些麻烦。

如何在编译时将联合体的使用类型锁定为一种类型? epoll的并集不能微分;你只能通过 epoll fd 使用 union 的一个成员。好吧,你可以,但这并不安全。

用户可以使用枚举类型作为联合的 ptr 字段来使用多个类型,但这将是安全的,因为它将使用 Rust 的 enum

我搜索了“generic”或“macro”,但找不到任何符合我意愿的方法。

extern crate libc;

#[derive(Clone, Copy)]
pub union Data {
pub ptr: *mut libc::c_void,
pub fd: std::os::unix::io::RawFd,
pub u32: libc::uint32_t,
pub u64: libc::uint64_t,
}

#[repr(C)]
#[repr(packed)]
#[derive(Clone, Copy)]
pub struct Event {
pub data: Data,
}

impl Event {
fn new(data: Data) -> Event {
Event { data: data }
}
}

fn main() {
let event = Event::new(Data {
ptr: Box::into_raw(Box::new(42)) as *mut libc::c_void,
});
unsafe { Box::from_raw(event.data.ptr) };
}

我想要这样的东西:

fn main() {
let event = event!(ptr, Box::new(42));
let _ = event.ptr();
let _ = event.fd(); // fails to compile; we can only use ptr
}

可以找到我的fork here .我不知道什么宏、通用或其他可能是合适的解决方案。你可以看看我的代码,特别是the integration test ,有很多不安全的代码,我想从用户端删除尽可能多的不安全代码。目前它看起来很丑。

最佳答案

您可以将联合包装在另一种类型中。该类型将具有特定特征的通用参数。然后,您可以根据具体实现来实现特定的方法集。

在这种情况下,我们包装联合 Data在类型 Event . Event对于任何实现 EventMode 的类型都有一个泛型类型参数.我们为具体类型实现特定方法Event<Fd>Event<Ptr> :

extern crate libc;
use std::os::unix::io::RawFd;
use std::marker::PhantomData;

#[derive(Copy, Clone)]
pub union Data {
pub ptr: *mut libc::c_void,
pub fd: RawFd,
}

trait EventMode {}

#[derive(Debug, Copy, Clone)]
struct Fd {
_marker: PhantomData<RawFd>,
}
impl Fd {
fn new() -> Self {
Fd {
_marker: PhantomData,
}
}
}
impl EventMode for Fd {}

#[derive(Debug, Copy, Clone)]
struct Ptr<T> {
_marker: PhantomData<Box<T>>,
}
impl<T> Ptr<T> {
fn new() -> Self {
Ptr {
_marker: PhantomData,
}
}
}
impl<T> EventMode for Ptr<T> {}

#[derive(Copy, Clone)]
pub struct Event<M> {
pub data: Data,
mode: M,
}

impl Event<Fd> {
fn new_fd(fd: RawFd) -> Self {
Event {
data: Data { fd },
mode: Fd::new(),
}
}

fn fd(&self) -> RawFd {
unsafe { self.data.fd }
}
}

impl<T> Event<Ptr<T>> {
fn new_ptr(t: T) -> Self {
let ptr = Box::into_raw(Box::new(t)) as *mut _;
Event {
data: Data {
ptr: ptr,
},
mode: Ptr::new(),
}
}

fn ptr(&self) -> &T {
unsafe { &*(self.data.ptr as *const T) }
}
}

fn main() {
let event = Event::new_ptr(42);
println!("{}", event.ptr());
// event.fd();
}

正在尝试调用 event.fd()给出错误:

error[E0599]: no method named `fd` found for type `Event<Ptr<{integer}>>` in the current scope
--> src/main.rs:76:11
|
76 | event.fd();
| ^^

作为奖励,我们可以使用相同的 PhantomData对我们存储在联合中的指针的具体类型进行编码,从而避免在检索它时不匹配。

严格来说,不需要该特征,但我认为它提供了一些不错的内置文档。

另见:

关于rust - 如何强制联合表现得好像只有一种类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47949601/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com