说明一下,下面引用的文章值得好好学习。
https://iandouglasscott.com/2018/05/28/exploring-rust-fat-pointers/
和
https://users.rust-lang.org/t/why-cant-a-convert-a-mut-c-void-into-mut-dyn-std-read/95780/2
首先要用到libc库;
libc = "0.2"
c_void是libc中的类型。
一、*mut c_void -> &'a mut dyt T
方案一:
use libc::{c_int, c_void};
trait T{
}
unsafe fn unwrap_T<'a>(spi: *mut c_void) -> &'a mut dyn T {
&mut **(spi as *mut *mut dyn T) // 两个解引用符号
}
这样也是可以的:即多加一个&mut或mut.; 当然后面第二行也需要多加一个""解引用符号。这个本质就是让as的两者对象大小一致就行。
unsafe fn unwrap_t<'a>(spi: *mut c_void) -> &'a mut dyn T {
let a = spi as *mut &mut &mut dyn T;
&mut *** a //增加了一个解引用符号*,三个解引用符号
}
方案二:
是否可以?
unsafe fn unwrap_T<'a>(spi: *mut c_void) -> &'a mut dyn T {
std::mem::transmute::<*mut c_void, &'a mut dyn T>(spi)
}
发现会报错。提示指针指向的类型的大小不一样。前者是占8个字节,后者占16个字节;
&'a mut dyn T 是一个胖指针(具体看上面参考资料,一个指向data,一个指向vtable),而 *mut c_void是一个瘦指针。
fn main(){
let s = std::mem::size_of::<*mut c_void>();
println!("size of s :{s}");
let t = std::mem::size_of::<& mut dyn T>();
println!("size of t :{t}");
let mm = std::mem::size_of::<*mut &mut dyn T>(); // std::mem::size_of::<*mut *mut dyn T>()
println!("size of mm :{mm}");
}
output:
size of s :8
size of t :16
size of mm :8
可见,两者size不一样,不能简单transmute。
改一下可以:
unsafe fn unwrap_T<'a>(spi: *mut c_void) -> &'a mut dyn T {
let _spi = std::mem::transmute::<*mut c_void, &'a mut *mut dyn T>(spi); // 方案2
&mut **_spi //2个解引用
}
从语法上看,也可以:
unsafe fn unwrap_Ti<'a>(spi: *mut c_void) -> &'a mut dyn QuoteSpi {
let _spi = std::mem::transmute::<*mut c_void, &'a mut *mut *mut dyn T>(spi); // 方案3 多了一个*mut
&mut ***_spi // 3个解引用
}
二、其它
1、Box<Box< dyn QuoteSpi>> -> *mut Box< dyn QuoteSpi> -> *mut c_void
2、Box::into_raw(Box::new(quote_spi_stub)) -> *mut XTP_API_QuoteSpi)
pub fn register_spi<T: QuoteSpi>(&mut self, spi: T) {
let trait_object_box: Box<Box<dyn QuoteSpi>> = Box::new(Box::new(spi));
let trait_object_pointer =
Box::into_raw(trait_object_box) as *mut Box<dyn QuoteSpi> as *mut c_void;
let quote_spi_stub = unsafe { QuoteSpiStub::new(trait_object_pointer) };
let ptr = Box::into_raw(Box::new(quote_spi_stub));
self.quote_spi_stub = Some(ptr);
unsafe { QuoteApi_RegisterSpi(self.quote_api, ptr as *mut XTP_API_QuoteSpi) };
}
3、 pub unsafe fn from_raw(raw: *mut T) -> Box
let x = Box::new(5);
let ptr = Box::into_raw(x);
let x = unsafe { Box::from_raw(ptr) };
4、into_raw(b: Box < T > ) -> *mut T
let x = Box::new(String::from("Hello"));
let ptr = Box::into_raw(x);
let x = unsafe { Box::from_raw(ptr) };
5、参考
fn ffi_reading_stuff<R: io::Read>(reader: &mut R) {
// Convert the trait into a raw pointer of a `dyn io::Read` object.
let boxed_reader: Box<&mut dyn io::Read> = Box::new(reader);
let reader_ptr: *mut &mut dyn io::Read = Box::into_raw(boxed_reader);
// Conver the pointer into a `ffi::c_void` pointer so that we can pass it into an FFI function.
let void_ptr: *mut ffi::c_void = reader_ptr as *mut ffi::c_void;
/// Do FFI stuff here...
// Receive the pointer back from FFI, and cast it back into the `dyn io::Read` object so that we can work with it properly.
//
// Alas this fails because "`c_void: std::io::Read` is not satisfied", but why?
let returned_reader_ptr: Box<&mut dyn io::Read> = unsafe {
Box::from_raw(void_ptr as *mut &mut dyn io::Read)
};
// Use the pointer, so Miri will check if we did everything right
let _ = returned_reader_ptr.read(&mut [0u8]);
}