4 个版本
0.2.0 | 2024 年 6 月 2 日 |
---|---|
0.1.2 | 2024 年 5 月 16 日 |
0.1.1 | 2024 年 5 月 15 日 |
0.1.0 | 2024 年 5 月 15 日 |
#81 在 FFI 中
每月下载 29 次
62KB
1K SLoC
FamBox
数据结构,用于启用对具有 灵活数组成员 的 C 结构的舒适和安全使用。
FamBox
有几种口味
FamBoxOwned
用于拥有数据。FamBoxMut
用于专有引用数据。FamBoxShared
用于别名数据。
假设你有一个这个 C 结构
struct protocol_msg {
uint8_t version; /* Protocol version */
uint8_t ty; /* Protocol message type */
uint16_t length; /* Length in bytes including the flexible array member. */
uint8_t elements[0]; /* msg data */
};
bindgen 将将其翻译为
#[repr(C)]
pub struct protocol_msg {
#[doc = " Protocol version"]
version: u8,
#[doc = " Protocol message type"]
ty: u8,
#[doc = " Length in bytes including the flexible array member."]
length: u16,
#[doc = " msg data"]
elements: __IncompleteArrayField<u8>,
}
可以使用 FamBoxOwned
来安全地构造此类的新实例。
use core::mem::size_of;
use fambox::FamBoxOwned;
// To be used safely, [`protocol_msg`] can't provide any safe mutable access to `length`.
pub use encapsulated_struct::protocol_msg;
mod encapsulated_struct {
use core::mem::size_of;
use fambox::FamHeader;
pub struct InvalidLength;
impl protocol_msg {
pub fn new(version: u8, ty: u8, buffer_len: usize) -> Result<Self, InvalidLength> {
Ok(Self {
version,
ty,
length: (size_of::<Self>()
+ buffer_len * size_of::<<Self as FamHeader>::Element>())
.try_into()
.or(Err(InvalidLength))?,
elements: __IncompleteArrayField::new(),
})
}
pub fn length(&self) -> u16 {
self.length
}
}
// Safety:
// `protocol_msg` doesn't expose a mutable setter which would make the length inconsistent.
unsafe impl FamHeader for protocol_msg {
type Element = u8;
fn fam_len(&self) -> usize {
let bytes_in_fam = usize::from(self.length) - size_of::<Self>();
bytes_in_fam / size_of::<Self::Element>()
}
}
}
let data_buffer = [0, 1, 2, 3, 4, 5];
let header = encapsulated_struct::protocol_msg::new(1, 2, data_buffer.len())?;
let header_and_fam = FamBoxOwned::from_fn(header, |i| data_buffer[i]);
let header = encapsulated_struct::protocol_msg::new(1, 2, data_buffer.len())?;
assert_eq!(header_and_fam.header(), &header);
assert_eq!(header_and_fam.fam(), data_buffer);
assert_eq!(
usize::from(header_and_fam.header().length()),
size_of::<protocol_msg>() + core::mem::size_of_val(&data_buffer)
);
或者一个 FamBoxShared
/FamBoxMut
可以用于轻松访问和操作从 C 访问的 fam 包含的结构
extern "C" {
fn original_header() -> protocol_msg;
fn original_data() -> NonNull<u8>;
fn original_data_len() -> usize;
fn aliased_ptr_from_c() -> NonNull<protocol_msg>;
fn alloc_in_c() -> NonNull<protocol_msg>;
fn free_in_c(ptr: NonNull<protocol_msg>);
}
let header_and_fam = unsafe { FamBoxShared::from_raw(aliased_ptr_from_c()) };
assert_eq!(header_and_fam.as_parts(), unsafe {
(&original_header(), unsafe { core::slice::from_raw_parts(original_data().as_ptr(), original_data_len()) })
});
let ptr = unsafe { alloc_in_c() };
let mut header_and_fam = unsafe { FamBoxMut::from_raw(ptr) };
assert_eq!(header_and_fam.as_parts(), unsafe {
(&original_header(), unsafe { core::slice::from_raw_parts(original_data().as_ptr(), original_data_len()) })
});
header_and_fam.fam_mut()[2] = 10;
drop(header_and_fam);
unsafe { free_in_c(ptr) }
功能标志
serde
: 为Serialize
和Deserialize
实现FamBoxOwned
许可证
根据您的选择,受以下任一许可证的许可
- Apache 许可证第 2.0 版 (LICENSE-APACHE 或 https://apache.ac.cn/licenses/LICENSE-2.0)
- MIT 许可证 (LICENSE-MIT 或 http://opensource.org/licenses/MIT)
。
贡献
除非您明确声明,否则任何有意提交以包含在作品中的贡献,根据 Apache-2.0 许可证的定义,应双重许可如上所述,不附加任何额外条款或条件。
依赖项
~170KB