Call C wrapper (for C++) from rust

Hi guys, I have this wrapper for my c++ library:

    #ifndef CRYPTOWRAPPER_WRAPPER_HPP
    #define CRYPTOWRAPPER_WRAPPER_HPP

    #ifdef __cplusplus
    extern "C" {
    #endif

    typedef struct CryptoWrap CryptoWrap;

    CryptoWrap* newCryptoclass();

    char* hello_w(CryptoWrap* v);

    void deleteCrypto_w(CryptoWrap* v);

    #ifdef __cplusplus
    }
    #endif
    #endif
How can I call it from rust?
 #[link(name = "cryptowrapper")]
 extern {
     fn newCryptoclass(); // I am lost here. , how can I reconstruct this: typedef struct CryptoWrap CryptoWrap; in rust, so that I can use it like this :  fn newCryptoclass() -> CryptoWrap;
     fn hello_w(CryptoWrap* v); // this line is where I am even more lost. How can I reconstruct this one?
 }

This can give you a good initial overview in rust and ffi
http://jakegoulding.com/rust-ffi-omnibus/objects/

Just an FYI: you can format code here using three backticks (```) and then the name of the language. For example:

```Rust
// Rust code here
```

Or for C++

```cpp
// C++ code goes here
```

Hi, I am trying to call C from rust, not rust from c. :slight_smile:

Thank you, changed!

For this you're going to need bindgen to convert the C header to a Rust equivalent.

And then you need to figure out linking, which in Rust is as fiddly as in any C build system. #[link(name = "foo")] is equivalent of only passing -lfoo, which is usually too optimistic, since in the real-world you'll need to ensure the library is built/installed and pass -L to find it. For that you'll need build.rs script, maybe the cc crate to build C code as a static library, or pkg_config crate to find its path.

1 Like

Thank you ! I got it working thanks to you! You pushed me to the right track. I have one more question. Can you tell me how to create

*const ::std::os::raw::c_char

in rust?
because

let test: *const ::std::os::raw::c_char = "Fuuu"; 

is not working for me :frowning:

Rust strings don't have \0 terminator, and Rust strings are not plain pointers, but structs of {data, length}. So you can't use &str with C.

You need CString: https://doc.rust-lang.org/std/ffi/struct.CString.html

2 Likes

Hi thank you. I just run into another problem I created safe wrapper:

pub struct CryptoWrapper {
    pub crypto_instance: *mut CryptoWrap,
}
impl CryptoWrapper {
    pub fn new(&mut self) {
        unsafe {
            self.crypto_instance = CryptoWrap_createInstance();
        }
    }
    pub fn hello(&self) -> i32 {
        unsafe {
            CryptoWrap_hello(self.crypto_instance)
        }
    }
    pub fn appendString(&self, appender: String) -> String{
        unsafe {
            let appender_c = CString::from_vec_unchecked(appender.into_bytes());

            let return_string = CryptoWrap_appendstring(self.crypto_instance, appender_c.as_c_str().as_ptr());

            let c_str: &CStr = CStr::from_ptr(return_string);
            let str_slice: &str = c_str.to_str().unwrap();
            let str_buf: String = str_slice.to_owned();

            str_buf
        }
    }
}
impl Drop for CryptoWrapper {
    fn drop(&mut self) {
        unsafe {
            CryptoWrap_deleteInstance(self.crypto_instance);
        }
        println!("deleted!");
    }
}

But, the problem is the Struct. I cannot initializate it without the crypto_instance field.

    let mut cryptoWrapper = CryptoWrapper {}; // doesnt work, but I cannot initializate that variable crypto_instance here, when it is done in new();.
    cryptoWrapper.new();  

Is there any workaround?

In C++, to constrict a instance you need to allocate a space first, call all the constructors of its superclasses by traversing inheritance graph, and finally call your class' constructor(initializer) with it.

In Rust, there's neither inheritance nor constructor here. The only way to construct a struct value(we prefer this term over instance), just make a struct literal and feeds all the fields it needs.

You don't even need a fn new(). It's just a function like any other like fn hello() or fn appendString(). Though we prefer this name for the function which returns the struct from simple arguments.

impl CryptoWrapper {
    pub fn new() -> CryptoWrapper {
        CryptoWrapper {
            crypto_instance: unsafe { CryptoWrap_createInstance() },
        }
    }
}
1 Like

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