gpt4 book ai didi

rust - 如何创建 FFI 绑定(bind)到需要 OR 字节的 C 函数?

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

我试图为 libmodbus 创建 FFI 绑定(bind), 用 C 写的。在这里我偶然发现了这个 function

modbus_set_error_recovery(ctx,
MODBUS_ERROR_RECOVERY_LINK |
MODBUS_ERROR_RECOVERY_PROTOCOL);

第二个参数定义为

typedef enum
{
MODBUS_ERROR_RECOVERY_NONE = 0,
MODBUS_ERROR_RECOVERY_LINK = (1<<1),
MODBUS_ERROR_RECOVERY_PROTOCOL = (1<<2)
} modbus_error_recovery_mode;

我的 bindgen 生成的绑定(bind)是这些:

#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum modbus_error_recovery_mode {
MODBUS_ERROR_RECOVERY_NONE = 0,
MODBUS_ERROR_RECOVERY_LINK = 2,
MODBUS_ERROR_RECOVERY_PROTOCOL = 4,
}

extern "C" {
pub fn modbus_set_error_recovery(ctx: *mut modbus_t,
error_recovery:
modbus_error_recovery_mode)
-> ::std::os::raw::c_int;
}

到目前为止,我的安全界面如下所示:

pub fn set_error_recovery(&mut self, error_recovery_mode: ErrorRecoveryMode) -> Result<()> {

unsafe {
match ffi::modbus_set_error_recovery(self.ctx, error_recovery_mode.to_c()) {
-1 => bail!(Error::last_os_error()),
0 => Ok(()),
_ => panic!("libmodbus API incompatible response"),
}
}
}

use std::ops::BitOr;

#[derive(Clone, Copy, PartialEq, Eq)]
pub enum ErrorRecoveryMode {
NONE = 0,
Link = 2,
Protocol = 4,
}

impl ErrorRecoveryMode {
pub fn to_c(self) -> ffi::modbus_error_recovery_mode {
match self {
NONE => ffi::modbus_error_recovery_mode::MODBUS_ERROR_RECOVERY_NONE,
Link => ffi::modbus_error_recovery_mode::MODBUS_ERROR_RECOVERY_LINK,
Protocol => ffi::modbus_error_recovery_mode::MODBUS_ERROR_RECOVERY_PROTOCOL,
}
}
}

impl BitOr for ErrorRecoveryMode {
type Output = Self;
fn bitor(self, rhs: ErrorRecoveryMode) -> ErrorRecoveryMode {
self | rhs
}
}

如果我像这样调用 set_error_recovery 会触发堆栈溢出

assert!(modbus.set_error_recovery(ErrorRecoveryMode::Link | ErrorRecoveryMode::Protocol).is_ok())

错误是

thread 'set_error_recovery' has overflowed its stack
fatal runtime error: stack overflow

最佳答案

作为 DK。提到:

  • C 的 enum 和 Rust 的 enum 有不同的限制。
  • 拥有不是枚举变体之一的 Rust 枚举是无效的。
  • 你所拥有的称为“位标志”

幸运的是,Bindgen 理解位标志。如果您在传递 bitfield-enum 标志或使用 Builder::bitfield_enum 时生成 header :

bindgen --bitfield-enum modbus_error_recovery_mode fake-modbus.h

Bindgen 将为每个 C 枚举值、新类型包装器和 Bit* 特性的实现生成常量:

// Many implementation details removed 

pub struct modbus_error_recovery_mode(pub ::std::os::raw::c_uint);

pub const modbus_error_recovery_mode_MODBUS_ERROR_RECOVERY_NONE: modbus_error_recovery_mode =
modbus_error_recovery_mode(0);
pub const modbus_error_recovery_mode_MODBUS_ERROR_RECOVERY_LINK: modbus_error_recovery_mode =
modbus_error_recovery_mode(2);
pub const modbus_error_recovery_mode_MODBUS_ERROR_RECOVERY_PROTOCOL: modbus_error_recovery_mode =
modbus_error_recovery_mode(4);

impl ::std::ops::BitOr<modbus_error_recovery_mode> for modbus_error_recovery_mode {}
impl ::std::ops::BitOrAssign for modbus_error_recovery_mode {}
impl ::std::ops::BitAnd<modbus_error_recovery_mode> for modbus_error_recovery_mode {}
impl ::std::ops::BitAndAssign for modbus_error_recovery_mode {}

extern "C" {
pub fn modbus_set_error_recovery(
ctx: *mut modbus_t,
error_recovery: modbus_error_recovery_mode,
) -> ::std::os::raw::c_int;
}

How do I expose the bindgen generated constants to the public

当然,为非 Rust 代码创建惯用的 Rust API 是困难的部分。我可能会尝试这样的事情:

#[derive(Debug)]
struct Modbus(*mut raw::modbus_t);

#[derive(Debug)]
struct Error;

#[derive(Debug, Copy, Clone)]
enum ErrorRecovery {
Link,
Protocol,
}

impl ErrorRecovery {
fn as_raw(&self) -> raw::modbus_error_recovery_mode {
use ErrorRecovery::*;

match *self {
Link => raw::modbus_error_recovery_mode_MODBUS_ERROR_RECOVERY_LINK,
Protocol => raw::modbus_error_recovery_mode_MODBUS_ERROR_RECOVERY_PROTOCOL,
}
}
}

impl Modbus {
fn set_error_recovery(&mut self, flags: Option<&[ErrorRecovery]>) -> Result<(), Error> {
let flag = flags.unwrap_or(&[]).iter().fold(
raw::modbus_error_recovery_mode_MODBUS_ERROR_RECOVERY_NONE,
|acc, v| acc | v.as_raw(),
);

let res = unsafe { raw::modbus_set_error_recovery(self.0, flag) };
Ok(()) // real error checking
}
}

关于rust - 如何创建 FFI 绑定(bind)到需要 OR 字节的 C 函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46844611/

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