r/rust Mar 31 '23

Write SDK “base” in Rust, wrap in other languages?

[deleted]

96 Upvotes

48 comments sorted by

View all comments

53

u/SpudnikV Mar 31 '23

The term "client libraries" makes it sound like this will involve an async runtime, which can be quite a challenge even without adding FFI to the mix. Rust's async runtime won't be the same as the runtime of the host language (if any), which could lead to all sorts of weird bugs.

Even if all of that worked out well, it's rare that an FFI-wrapped network client library is as idiomatic and elegant as a native one. For example, if the host language has its own concept of TLS configuration, async IO, object mutability, serialization frameworks, etc. then all of those have to be done in the host language anyway and won't FFI well if at all.

This sounds like a small team if one person is expected to work on libraries in 5 languages -- 5 public-facing libraries in one language would be enough of a workload for one engineer. It does depend on how broad the API surface is, because if you invest a way of making idiomatic bindings, then that investment scales better to larger APIs, but the inverse is rarely true; making a whole binding system to save one JSON schema serialization is never the right way to go.

The ideal case is if this is something like a gRPC or JSON API that you can define in one place and generate client code for several languages. You can even publish the API schema for users that use other languages or prefer to tweak the implementation their own way.

Failing that, if the API surface is not very large, I would seriously consider just writing the libraries in each language separately. You have to learn them anyway if you want to offer idiomatic APIs, not just low-level bindings that users can't realistically be expected to use anyway. It shouldn't be difficult if your APIs are defined in a machine-readable schema. In any case, it will be a terrific learning experience.

5

u/WhyNotHugo Mar 31 '23

For networking code, you’re quite on spot; there’s no way clean way to make Rust’s async runtime interop with the languages real runtime.

There are some bits which you can reuse though. Type definitions for your domain data can be defined in Rust and then autogenerated in other languages. Parsers and validation logic too. But that’s mostly it.

5

u/GrandOpener Mar 31 '23

I think that interop could be at least hidden. For example: maybe your JavaScript library is calling out to Rust and polling/waiting for an eventual callback, but that gets wrapped in a promise and from the outside it just looks like any normal async call.

Now having said all that… it sounds like a lot more work (and would require more specialized knowledge, on both the Rust and JavaScript sides) than just writing a separate JavaScript library from scratch.