On 11/09/20 12:24, Paolo Bonzini wrote: >> >> - from_qemu_none(ptr: *const sys::P) -> T >> Return a Rust type T for a const ffi pointer P. >> >> - from_qemu_full(ptr: *mut sys::P) -> T >> Return a Rust type T for a ffi pointer P, taking ownership. >> >> - T::to_qemu_none() -> Stash<P> >> Returns a borrowed ffi pointer P (using a Stash to destroy "glue" >> storage data, if any). >> >> - T::to_qemu_full() -> P >> Returns a ffi pointer P. (P resources are leaked/passed to C/ffi) > > I know these come from glib-rs, but still the names are awful. :)
After studying a bit I managed to give a rational explanation of the above gut feeling. Conversions in Rust usually follow this naming convention: Name Type Price -------- -------------------- ----------- as_*, borrow Borrowed -> Borrowed Cheap to_*, constructor Borrowed -> Owned Expensive from, into_* Owned -> Owned Any and we have from_qemu_none Borrowed -> Owned to_qemu_none Borrowed -> Borrowed from_qemu_full Owned -> Owned to_qemu_full Owned -> Owned So - from_qemu_none should be a "to_*" or "constructor" conversion (I used new_from_foreign) - to_qemu_none, even though in some cases it can be expensive, should be an "as_*" conversion (as_foreign). - from_qemu_full and to_qemu_full should be "from" or "into_*" to_qemu_full() could also be split into a more expensive but flexible "to" variant and the cheaper "into" variant. Just for the sake of example, I updated my demo by replacing the IntoRaw trait with these two: trait ToForeign<T> { fn to_foreign(&self) -> *mut T; } trait IntoForeign<T> { fn into_foreign(self) -> *mut T; } where the example implementations show the different cost quite clearly: impl ToForeign<c_char> for String { fn to_foreign(&self) -> *mut c_char { unsafe { libc::strndup(self.as_ptr() as *const c_char, self.len() as size_t) } } } impl IntoForeign<c_char> for String { fn into_foreign(self) -> *mut c_char { let ptr = self.as_ptr(); forget(self); ptr as *mut _ } } Thanks, Paolo