Rust为C API错误码编写包装枚举的实现方案咨询
Rust封装C API错误码相关问题
我正在为一个C API编写Rust封装。该API包含可能执行失败的函数,失败时会返回编码为int类型的错误码,其中两个错误码命名为SOME_ERROR和OTHER_ERROR,对应取值分别为1和2。我最初尝试编写枚举来包装这些错误码,代码如下:
// 定义在独立的C头文件中 const SOME_ERROR: c_int = 1; const OTHER_ERROR: c_int = 2; #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(i32)] enum ErrorCodeWrapper { SomeError = SOME_ERROR, OtherError = OTHER_ERROR, }
枚举底层类型适配问题
目前似乎无法直接将std::os::raw::c_int指定为枚举的底层类型,但C语言的int类型并不保证一定是32位宽度,有什么方法可以实现这一点?
我最初编写的原始错误码与包装枚举双向转换方法如下:
use std::os::raw::c_int; impl ErrorCodeWrapper { fn from_raw(raw: c_int) -> Option<Self> { match raw { SOME_ERROR => Some(Self::SomeError), OTHER_ERROR => Some(Self::OtherError), _ => None } } unsafe fn from_raw_unchecked(raw: c_int) -> Self { *(&raw as *const _ as *const Self) } fn as_raw(self) -> c_int { unsafe { *(&self as *const _ as *const c_int) } } }
安全位转换与代码简化问题
我目前找到的实现c_int与ErrorCodeWrapper之间位转换的唯一方式是C风格的指针强转后解引用。由于ErrorCodeWrapper与int的内存大小、对齐要求一致,且每个枚举变体的值都对应正确的错误码,该方法可以正常运行,但这种实现过于hack,有没有更符合Rust惯用法的方案,类似C++的std::bit_cast?
此外,当枚举变体数量较多时,是否可以用简单的合法性校验替换ErrorCodeWrapper::from_raw中的match语句,简化代码?
我编写的错误trait实现代码如下:
use std::{fmt::Display, error::Error}; impl Display for ErrorCodeWrapper { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", match self { Self::SomeError => "some error", Self::OtherError => "some other error", }) } } impl Error for ErrorCodeWrapper {}
多枚举共享变体的样板代码问题
现在假设需要编写第二个包装枚举SuperErrorCodeWrapper,它包含ErrorCodeWrapper的部分或全部变体,错误描述等信息完全一致,此时有两种实现思路:
- 将
ErrorCodeWrapper和SuperErrorCodeWrapper的公共变体抽取到独立枚举中,两个包装枚举各设一个持有该独立枚举的变体,但我不喜欢这种嵌套结构,在处理单个错误时会显得非常冗余不自然。 - 在两个枚举中重复编写所有公共变体。
第二种方案会产生大量样板代码,是否可以用宏来解决这个问题?是否有现成的库可以一站式解决上述所有需求?
内容的提问来源于stack exchange,提问作者Debaug
相关产品推荐
相关产品推荐

