Hi - great start on that! I’ll try to help as much as I can:
Correct, functions don’t return values as usual – but they don’t modify the provided structures either. safe_authenticator was coded in that way first but after lots of iterations we have came to the current way of returning values through callbacks – which are that
void (*o_cb)(...) thing you’re seeing in each and every FFI function. This approach turned out to be quite robust and doesn’t require you to manage memory manually. And it has an extra bonus of handling asynchronous calls automatically.
Yes, there is a difference between Rust strings (which are actually
Vec<u8>s) and null-terminated C strings which can’t contain null bytes and don’t carry information about the string length with them – as opposed to Rust strings. But both can be converted, and we use C string for our FFI APIs exclusively.
To convert Rust string into a C string, you can use
CString: its usage is not complicated and you can find some examples in the SAFE Client Libs code.
In this case you can also use
CString, it will allocate the necessary memory and it will guarantee that the resulting string will be C-compatible.
I think that will be the hardest part as you will need to deal with data copying and asynchronous callbacks. I am not completely sure which is the idiomatic way to code that in Python, but from what I know starting from Python 3.5 there is a native support for asynchronous calls and
await – so you can write more streamlined code:
r1 = await call1(a, b, c)
r2 = await call2(r1)
instead of something like
call1(a, b, c, callback1)
Once you figure out the callbacks and data copying, it becomes a lot easier – you can automatically generate the language bindings, in the very same way as we do with C# and Java.
If you have more questions or something’s blocking you from experimenting, don’t heistate to ask!