为外部C库分配不透明缓冲区的正确Rust方法是什么?

问题描述 投票:1回答:1

我有一个外部库(例如libcisland.so),其接口如下:

size_t lib_handle_size();
typedef void* handle;
int lib_init(handle h);
int lib_store(handle h, int value);
int lib_restore(handle h, int *pvalue);

该库的用户应该执行以下操作:

// allocate some buffer in client address space
handle h = malloc(lib_handle_size());
// pass this buffer to library for initialization
if (lib_init(h)) { /* handle errors */ }
// library initializes this handle by some opaque fashion
// then user uses it
lib_store(h,42);
int r;
lib_restore(h,&r);
// after all work is done, user frees this handle
free(h);

我不知道如何正确地将此接口包装到Rust。这就是我最终的结果:

pub struct Island {
    h : Handle,
    v : Vec<u8>,
}
impl Island {
    pub fn new() -> Island {
        let len = unsafe { lib_handle_size() };
        let mut v: Vec<u8> = Vec::with_capacity(len);
        let h: Handle = v.as_mut_ptr();
        Island { v:v, h:h, }
    }
    pub fn store(&mut self, v: i32) {
        unsafe { lib_store(self.h, v); }
    }
    pub fn restore(&mut self) -> i32 {
        let mut v = 0;
        unsafe { lib_restore(self.h, &mut v); }
        v
    }
}
impl Drop for Island {
    fn drop(&mut self) {
        drop(&mut self.v);
    }
}

/// unsafe part
use libc::size_t;
pub type Handle = *mut u8;
#[link(name="cisland")]
extern  {
    pub fn lib_handle_size() -> size_t;
    pub fn lib_init(h: Handle) -> i32;
    pub fn lib_store(h: Handle, value: i32) -> i32;
    pub fn lib_restore(h: Handle, pvalue: &mut i32) -> i32;
}

为此目的可以使用Vec(u8)吗?此Drop特性是否正确实施?

c rust ffi
1个回答
0
投票

为此目的可以使用Vec(u8)吗?

一个向量并不意味着要那样使用,即使您的代码可以工作,这也不是一个好方法。

要正确执行此操作,您需要一个实验功能(此功能相当稳定),需要使用System结构和System特征。不幸的是,您的库没有为其句柄提供任何对齐要求,因此我们必须使用Alloc

根据您的Alloc

1是不正确的(顺便说一下,隐藏指针不好)。应该是pub type Handle = *mut u8;

typedef void* handle;

我稍微改变一下pub type Handle = *mut libc::c_void;#![feature(allocator_api)] use std::alloc::{Alloc, Layout, System}; use std::ptr::NonNull; pub struct Island { handle: NonNull<u8>, layout: Layout, } impl Island { pub fn new() -> Island { let size = unsafe { lib_handle_size() }; let layout = Layout::from_size_align(size, 1).unwrap(); let handle = unsafe { System.alloc(layout).unwrap() }; Self { handle, layout } } pub fn store(&mut self, v: i32) -> Result<(), ()> { unsafe { lib_store(self.handle.as_ptr() as Handle, v); } Ok(()) } pub fn restore(&mut self, v: &mut i32) -> Result<(), ()> { unsafe { lib_restore(self.handle.as_ptr() as Handle, v); } Ok(()) } } impl Drop for Island { fn drop(&mut self) { unsafe { System.dealloc(self.handle, self.layout) } } } /// unsafe part use libc::size_t; pub type Handle = *mut libc::c_void; #[link(name = "cisland")] extern "C" { pub fn lib_handle_size() -> size_t; pub fn lib_init(h: Handle) -> i32; pub fn lib_store(h: Handle, value: i32) -> i32; pub fn lib_restore(h: Handle, pvalue: &mut i32) -> i32; } 函数以返回结果。我敢打赌,您的C函数也是如此。

© www.soinside.com 2019 - 2024. All rights reserved.