[rust-dev] wrapping a C library (ownership/mutability questions)

Alex Crichton alex at crichton.co
Fri Jan 17 16:32:24 PST 2014


> This is the part that I don't follow; why can't I just mark
> my mutable-only methods as taking a mutable self?

The problem with this is that it requires that the *owner* of a type
have a *mutable slot*, and you cannot prevent owners from declaring
their slots as mutable. In the example you gave, you could write "let
mut var2 = Box { x: 2 }" and it would compile, there's nothing
preventing usage of the "mut" at the owner.

One possible solution is to use a thing called "shadow type parameters"

pub enum Mutable {}
pub enum Frozen {}
pub struct Box<State> {
    priv x: i32,
}

// methods that only work on a mutable box
impl Box<Mutable> {
    fn new() -> Box<Mutable> { Box { x: 2 } }
    fn set_x(&mut self, val: i32) -> { self.x = val; }
    fn freeze(self) -> Box<Frozen> { Box { x: self.x } }
}

// methods that work on all boxes (mutable and immutable)
impl<T> Box<T> {
    fn x(&self) -> i32 { self.x }
}

impl Clone for Box<Frozen> { ... }

impl<T> Drop for Box<T> { ... }

With something like this you can write code that works over generic
boxes (immutable or mutable), but you have a clear separation of what
a mutable box can do and what a frozen box can do.

>> impl Clone for MyImmutableStruct {
>>     fn clone(&self) -> MyImmutableStruct {
>>         unsafe { my_c_ref_function(self.ptr); }
>>         MyImmutableStruct { ptr: self.ptr }
>>     }
>> }
>>
>> impl Drop for MyImmutableStruct {
>>     fn drop(&mut self) {
>>         unsafe { my_c_unref_funtion(self.ptr); }
>>     }
>> }
>
> This looks about right.  What I was asking is how to furnish
> the second parameter to my ref/unref functions: the "owner".
> In my API all refs have an "owner", which is simply a
> "const void*" that must be distinct from all other ref owners
> for this object.  It's a debugging facility that makes it
> easier to track down ref leaks.  In C or C++, I usually use
> the address of the variable that is storing the pointer to
> my MessageDef object as the ref owner.

Sadly this doesn't translate to rust. In your example, you're
declaring the owner as a stack pointer, but then that stack pointer is
invalidated as soon as the function returns. You'll probably not want
to implement the trait Clone or you'll want to find some other way to
track owners perhaps.

> However I am wondering if there is any way to actually take
> the address of a Rust variable as I did above (and if it is
> possible, to guarantee that the address is stable over the
> lifetime of the object).

Without making an explicit allocation, you have no guarantee about the
stability of an address because objects can be moved from place to
place.


More information about the Rust-dev mailing list