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

Erick Tryzelaar erick.tryzelaar at gmail.com
Fri Jan 17 11:46:35 PST 2014


I can help with the first question. You can use move semantics to do this.
For example:

```
pub struct MessageDef {
    fullname: ~str,
}

impl MessageDef {
    fn new() -> MessageDef { MessageDef { ... } }
    fn set_fullname(&mut self, s: &str) { self.fullname = s.to_str(); }
}

pub struct Message {
    priv def: MessageDef,
}

impl Message {
    fn new(def: MessageDef) -> Message { Message { def: def } }
    fn get_fullname<'a>(&self) -> &'a ~str { self.def.fullname }
}



fn main() {
    let def = MessageDef::new();
    def.set_fullname("foo");
    let msg = Message::new(def);
    // def is now inaccessible.
}
```

I'm afraid I can't help out much with two and three. The simplest is to
have `Message::new` wrap the `Message` struct in an Arc. Then it's
guaranteed to be safe to access threads. The downside is that it wouldn't
use any of your reference counting code so it might be more tricky to
debug. A more complicated approach would be to make an Arc-like structure
that uses your code for reference counting instead of Arcs. Unfortunately
while I know it's possible, I couldn't tell you how to do it.



On Fri, Jan 17, 2014 at 10:39 AM, Josh Haberman <jhaberman at gmail.com> wrote:

> Hi Rust experts,
>
> I would love your advice on how to wrap my C library with Rust, and
> particularly how to map my library's ownership/mutability semantics
> onto idiomatic Rust types, since my library's ownership/mutability
> model is a great match for Rust's approach.
>
> My library's objects have a two-phase lifecycle: when first created
> they are mutable and are not thread-safe. When the client has set all
> properties to their satisfaction, they perform a "freeze" operation,
> after which the object is thread-safe and immutable.
>
> Once immutable, they are also reference-counted. These objects also
> can have references between them in a possibly-cyclic graph, but the
> library handles intra-object cycles internally; the client only need
> maintain their own refcount properly and the library will handle the
> rest.
>
> Here is a quick example of using my library's C API (the .h file for
> this API is here:
> https://github.com/haberman/upb/blob/master/upb/def.h)
>
>   // Create a new object.
>   upb_msgdef *md = upb_msgdef_new(&md);
>
>   // It is initially mutable, so I can set its properties now.
>   upb_msgdef_setfullname(md, "MyMessage", NULL);
>
>   // Now freeze the msgdef; after this it may only be accessed through a
>   // const pointer, though there is no way to enforce this in C/C++ except
>   // with assert().
>   upb_def_freeze(&md, 1, NULL);
>
>   // Now that it is frozen we can take other refs on it.
>   // The second parameter to ref/unref is used in debug mode to match
>   // refs and unrefs, to make refcounting bugs easier to track down.
>   const upb_msgdef *md2 = md;
>   upb_msgdef_ref(md2, &md2);
>
>   // This function is thread-safe and allowed on frozen objs.
>   const char *fullname = upb_msgdef_fullname(md2);
>
>   // We must release all refs to prevent the object from leaking.
>   upb_msgdef_unref(md, &md);
>   upb_msgdef_unref(md2, &md2);
>
> This seems like a great match for Rust, because an object could be
> created as "mut" and local to a single task, but then "become" non-mut
> and be sharable between tasks once frozen. And the refcounting scheme
> sounds like a great match for the Arc model.
>
> I could just use a little help on how to map this onto Rust's existing
> libraries and traits:
>
> 1. Can I write a "freeze" function in Rust where my mut pointers
> "become" non-mut pointers in a way that the mut pointers are no longer
> accessible?
>
> 2. Is my notion of freezing the same as Rust's "Freeze" trait? Is
> there a pattern I should follow to make my type "fit in" with the
> stdlib better?
>
> 3. I think I can write a very Arc-like interface to my refcounting.
> Will my individual refcounting wrappers let me take their address so I
> can pass it to the second param of my ref/unref functions?
>
> Thanks,
> Josh
> _______________________________________________
> Rust-dev mailing list
> Rust-dev at mozilla.org
> https://mail.mozilla.org/listinfo/rust-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/rust-dev/attachments/20140117/81faea3a/attachment-0001.html>


More information about the Rust-dev mailing list