How can I expose a safe wrapper around an owned pointer? - rust

I'm wrapping a C library that has two structs: one has a pointer to the other.
struct StructA {
void * some_mem;
};
struct StructB {
void * some_mem;
struct StructA * some_struct;
};
Both of these structs own memory, so my wrapper has constructors and destructors for both of them.
struct StructA(*mut c_void);
impl StructA {
fn new() -> Self {
StructA(c_constructor())
}
}
impl Drop for StructA {
fn drop(&mut self) {
let StructA(ptr) = self;
c_destructor(ptr);
}
}
There's also a function that takes a pointer to StructB and returns its pointer to StructA:
const struct StructA * get_struct(const struct StructB * obj);
The user of this function should not free the returned pointer, since it will be freed when the user frees obj.
How can I wrap this function? The problem is that the destructor for StructB frees all its memory, including the one for StructA. So if my wrapping of get_struct returns an object, then the wrapped StructA will be freed twice (right?). It could instead return a reference to an object, but where would that object live?
I could have separate structs for StructA based on whether it's standalone and needs to be freed or if it's a reference, but I'm hoping that's unnecessary.

I could have separate structs for StructA based on whether it's standalone and needs to be freed or if it's a reference, but I'm hoping that's unnecessary.
It's necessary. The difference between an owned StructA * and a borrowed StructA * is precisely the same as the difference between a Box<T> and a &T. They're both "just a pointer", but the semantics are completely different.
Something along these lines is probably what you want:
use std::marker::PhantomData;
struct OwnedA(*mut c_void);
impl Drop for OwnedA {
fn drop(&mut self) { }
}
impl OwnedA {
fn deref(&self) -> RefA { RefA(self.0, PhantomData) }
}
struct RefA<'a>(*mut c_void, PhantomData<&'a u8>);
struct OwnedB(*mut c_void);
impl Drop for OwnedB {
fn drop(&mut self) { }
}
impl OwnedB {
fn get_a(&self) -> RefA { RefA(get_struct(self.0), PhantomData) }
}
In particular, it's worth noting that lifetime parameter on RefA lets the compiler make sure you don't use a RefA after the backing structure has been freed.

I could have separate structs for StructA based on whether it's standalone and needs to be freed or if it's a reference, but I'm hoping that's unnecessary.
I believe this would be the accepted pattern. For backup, I'd point to the fact that this is a normal pattern in the Rust library. &str and String, &[T] and Vec<T>, Path and PathBuf, and probably lots of others I can't think of.
The good news is that you can use similar patterns as these pairs, leveraging Deref or DerefMut to call down to shared implementation:
use std::ops::{Deref, DerefMut};
enum RawFoo {}
fn c_foo_new() -> *const RawFoo { std::ptr::null() }
fn c_foo_free(_f: *const RawFoo) {}
fn c_foo_count(_f: *const RawFoo) -> u8 { 42 }
fn c_foo_make_awesome(_f: *const RawFoo, _v: bool) { }
struct OwnedFoo(Foo);
impl OwnedFoo {
fn new() -> OwnedFoo {
OwnedFoo(Foo(c_foo_new()))
}
}
impl Drop for OwnedFoo {
fn drop(&mut self) { c_foo_free((self.0).0) }
}
impl Deref for OwnedFoo {
type Target = Foo;
fn deref(&self) -> &Self::Target { &self.0 }
}
impl DerefMut for OwnedFoo {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
}
struct Foo(*const RawFoo);
impl Foo {
fn count(&self) -> u8 { c_foo_count(self.0) }
fn make_awesome(&mut self, v: bool) { c_foo_make_awesome(self.0, v) }
}
fn main() {
let mut f = OwnedFoo::new();
println!("{}", f.count());
f.make_awesome(true);
}
Then, when you get a borrowed pointer from your other object, just wrap it up in a &Foo:
use std::mem;
fn c_bar_foo_ref() -> *const RawFoo { std::ptr::null() }
// Ignoring boilerplate for wrapping the raw Bar pointer
struct Bar;
impl Bar {
fn new() -> Bar { Bar }
fn foo(&self) -> &Foo {
unsafe { mem::transmute(c_bar_foo_ref()) }
}
fn foo_mut(&mut self) -> &mut Foo {
unsafe { mem::transmute(c_bar_foo_ref()) }
}
}
fn main() {
let mut b = Bar::new();
println!("{}", b.foo().count());
b.foo_mut().make_awesome(true);
// Doesn't work - lifetime constrained to Bar
// let nope = Bar::new().foo();
}

Related

How to 'implement' functions from inner object onto the outer struct?

given this example
struct Outer<T>(*mut T);
impl<T> Outer<T> {
pub fn new(value: &mut T) -> Outer<T> {
Outer(value as *mut T)
}
}
struct Inner(pub i32);
impl Inner {
pub fn do_thing(&self) {
println!("did the thing {}", self.0);
}
}
fn main() {
let outer = Outer::new(Inner(2));
outer.do_thing() // error: do_thing doesnt exist
}
how would i expose the methods of Inner as methods of Outer
im trying to achieve what Box is doing
You have to reborrow the pointer in order to implement Deref (playground):
impl<T: ?Sized> Deref for Outer<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.0 }
}
}
Answer from before the edit below:
The clean way is to have methods that return the inner type:
impl<T> Outer<T> {
pub fn get(&self) -> &T {
&self.0
}
pub fn get_mut(&mut self) -> &mut T {
&mut self.0
}
pub fn into_inner(self) -> T {
self.0
}
}
This is more useful when the inner type isn't pub (you can just do self.0 for the same effect as all three methods), but is a common pattern that users of rust libraries expect.
The other way is to implement Deref and DerefMut. This is messier because it's a very strong API commitment: you now have all the methods of the inner type added to the outer type unconditionally, and gain any future methods. It also means that any namespace collisions between the wrapper and the target are hard to notice, which is why things like Arc::get_mut are associated functions instead of methods. If you use this, consider changing methods on the wrapper to associated functions (don't take a self parameter).
impl<T> Deref for Outer<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}

Rust and RAII wrapper for shared mutable data

Let's say I have a mutable structure (i32 in the example code for simplicity) which should be shared between threads. I can use Mutex for it (and Arc for memory management). But I want to have RAII wrapper for data lock to make some specific interface of data modification, track unlocks etc.
Here the draft (I don't know which lifetime specify for MutexGuard):
use std::sync::{Arc, Mutex, MutexGuard};
pub struct SharedData {
data: Arc<Mutex<i32>>
}
impl SharedData {
pub fn new(value: i32) -> Self {
SharedData {
data: Arc::new(Mutex::new(value))
}
}
pub fn lock(&self) -> LockedSharedData<'_> {
LockedSharedData::new(self.data.clone())
}
}
pub struct LockedSharedData<'a> {
_data: Arc<Mutex<i32>>,
guard: MutexGuard<'a, i32>
}
impl<'a> LockedSharedData<'a> {
fn new(data: Arc<Mutex<i32>>) -> Self {
LockedSharedData {
guard: data.lock().unwrap(),
_data: data
}
}
pub fn get(&self) -> i32 {
*self.guard
}
pub fn inc(&mut self) {
*self.guard += 1;
}
}
It predictable doesn't compile - https://rust.godbolt.org/z/4rEe3fWxK.
How to fix this pattern implementation?

How to avoid orphan rules for repr transparent wrappers

My problem is I want to have a transparent wrapper and implemented Into<underlying> for it. Unfortunately, rust's orphan rules forbid it. Here is a simple example:
#[repr(transparent)]
pub struct MyWrapper<T>(pub T);
impl<T> Into<T> for MyWrapper<T> {
fn into(self) -> T {
self.0
}
}
The question is is there any way I can implement it? I'm using macro to generate impl for all types I'm currently using but it looks very awkward and dirty.
You can implement the Deref trait instead. The Deref docs contain the following example which is almost identical to your code:
use std::ops::Deref;
struct DerefExample<T> {
value: T
}
impl<T> Deref for DerefExample<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.value
}
}
fn main() {
let x = DerefExample { value: 'a' };
assert_eq!('a', *x);
}
You can implement it in a regular impl block:
#[repr(transparent)]
pub struct MyWrapper<T>(pub T);
impl<T> MyWrapper<T> {
pub fn into(self) -> T {
self.0
}
}
fn main() {
let wrapped : MyWrapper<f32> = MyWrapper::<f32>(3.4f32);
let unwrapped : f32 = wrapped.into();
println!("{}", unwrapped);
}

How to declare a generic type that is a raw pointer?

Given a struct that wraps a pointer,
pub struct Ptr<T> {
ptr: T
}
Is it possible to declare that T must be a raw pointer type? eg *mut SomeStruct or *const SomeStruct.
Without this, I'm unable to perform operations like &*self.ptr within a method, since Rust doesn't know ptr can be treated like a pointer.
Note that this can be made to work:
pub struct Ptr<T> {
ptr: *mut T
}
But in that case, it hard-codes *mut, where we might want *const in other cases.
See: this answer to give some context.
I'm not convinced this is worth doing, but if you're sure then you can just write a trait:
pub trait RawPtr: Sized {
type Value;
fn as_const(self) -> *const Self::Value {
self.as_mut() as *const _
}
fn as_mut(self) -> *mut Self::Value {
self.as_const() as *mut _
}
}
impl<T> RawPtr for *const T {
type Value = T;
fn as_const(self) -> Self { self }
}
impl<T> RawPtr for *mut T {
type Value = T;
fn as_mut(self) -> Self { self }
}
Your can then require P: RawPtr when implementing functions:
pub struct Ptr<P> {
ptr: P
}
impl<P: RawPtr> Ptr<P> {
unsafe fn get(self) -> P::Value
where P::Value: Copy
{
*self.ptr.as_const()
}
}
Additionally, it's possible to define methods that are only available when P is a mutable pointer:
impl<T> Ptr<*mut T> {
unsafe fn get_mut(&mut self) -> *mut T {
self.ptr
}
}

error: `line` does not live long enough (but I know it does)

I am trying to make some kind of ffi to a library written in C, but got stuck. Here is a test case:
extern crate libc;
use libc::{c_void, size_t};
// this is C library api call
unsafe fn some_external_proc(_handler: *mut c_void, value: *const c_void,
value_len: size_t) {
println!("received: {:?}" , std::slice::from_raw_buf(
&(value as *const u8), value_len as usize));
}
// this is Rust wrapper for C library api
pub trait MemoryArea {
fn get_memory_area(&self) -> (*const u8, usize);
}
impl MemoryArea for u64 {
fn get_memory_area(&self) -> (*const u8, usize) {
(unsafe { std::mem::transmute(self) }, std::mem::size_of_val(self))
}
}
impl <'a> MemoryArea for &'a str {
fn get_memory_area(&self) -> (*const u8, usize) {
let bytes = self.as_bytes();
(bytes.as_ptr(), bytes.len())
}
}
#[allow(missing_copy_implementations)]
pub struct Handler<T> {
obj: *mut c_void,
}
impl <T> Handler<T> {
pub fn new() -> Handler<T> { Handler{obj: std::ptr::null_mut(),} }
pub fn invoke_external_proc(&mut self, value: T) where T: MemoryArea {
let (area, area_len) = value.get_memory_area();
unsafe {
some_external_proc(self.obj, area as *const c_void,
area_len as size_t)
};
}
}
// this is Rust wrapper user code
fn main() {
let mut handler_u64 = Handler::new();
let mut handler_str = Handler::new();
handler_u64.invoke_external_proc(1u64); // OK
handler_str.invoke_external_proc("Hello"); // also OK
loop {
match std::io::stdin().read_line() {
Ok(line) => {
let key =
line.trim_right_matches(|&: c: char| c.is_whitespace());
//// error: `line` does not live long enough
// handler_str.invoke_external_proc(key)
}
Err(std::io::IoError { kind: std::io::EndOfFile, .. }) => break ,
Err(error) => panic!("io error: {}" , error),
}
}
}
Rust playpen
I get "line does not live long enough" error if I uncomment line inside the loop. In fact, I realize that Rust is afraid that I could store short-living reference to a slice somewhere inside Handler object, but I quite sure that I wouldn't, and I also know, that it is safe to pass pointers to the external proc (actually, memory is immidiately copied at the C library side).
Is there any way for me to bypass this check?
The problem is that you are incorrectly parameterizing your struct, when you really want to do it for the function. When you create your current Handler, the struct will be specialized with a type that includes a lifetime. However, the lifetime of line is only for the block, so there can be no lifetime for Handler that lasts multiple loop iterations.
What you want is for the lifetime to be tied to the function call, not the life of the struct. As you noted, if you put the lifetime on the struct, then the struct is able to store references of that length. You don't need that, so put the generic type on the function instead:
impl Handler {
pub fn new() -> Handler { Handler{obj: std::ptr::null_mut(),} }
pub fn invoke_external_proc<T>(&mut self, value: T) where T: MemoryArea {
let (area, area_len) = value.get_memory_area();
unsafe {
some_external_proc(self.obj, area as *const c_void,
area_len as size_t)
};
}
}
Amended answer
Since you want to specialize the struct on a type, but don't care too much about the lifetime of the type, let's try this:
#[allow(missing_copy_implementations)]
pub struct Handler<T: ?Sized> {
obj: *mut c_void,
}
impl<T: ?Sized> Handler<T> {
pub fn new() -> Handler<T> { Handler{ obj: std::ptr::null_mut() } }
pub fn invoke_external_proc(&mut self, value: &T) where T: MemoryArea {
let (area, area_len) = value.get_memory_area();
unsafe {
some_external_proc(self.obj, area as *const c_void,
area_len as size_t)
};
}
}
Here, we allow the type to be unsized. Since you can't pass an unsized value as a parameter, we now have to take a reference instead. We also have to change the impl:
impl MemoryArea for str {
fn get_memory_area(&self) -> (*const u8, usize) {
let bytes = self.as_bytes();
(bytes.as_ptr(), bytes.len())
}
}

Resources