Ffi wrapper: where to deal with strings

I have generated a couple of -sys crates with bindgen and have also written some more ergonomic wrappers around them but I'm still not sure how to deal with strings calling into the FFI. I'm curious what other people do?

Say for instance, your bound API has a function device_t device_create(protocol_t protocol, const char *name) that creates some device with a name and you want to wrap that..

struct Device(foo_sys::device_t);

would you just take a CString to create the device?

impl Device {
  pub fn new(protocol: Protocol, name: CString) -> Self;
}

or make the creation fallible, use String and hide the CString?

impl Device {
  pub fn new(protocol: Protocol, name: String) -> Option<Self>;
}

or panic?

impl Device {
  pub fn new(protocol: Protocol, name: String) -> Self {
    let name = CString::new(name).expect("failed to convert name to CString");
    ....
  }
}

or??

I'm feeling like the fallible one with String is the best from a usage standpoint..

I think i probably answered my own question..
and I guess if there are methods that aren't creation methods a string, you could do the same thing and return a Result<(), Err<'static str>> or something

Taking String is going to be efficient only if the String has spare capacity for the nul terminator. Otherwise, CString will reallocate anyway.

If the caller calls your function with "foo".to_string(), then it won't have spare capacity, and it's going to be a wasted hassle and a wasted allocation.

Sadly, impl TryInto<CString> doesn't seem to work. So consider taking just &str.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.