Anouncing `stabby` 1.0!

102 points Fox-PhD

A couple of months ago, I anounced stabby's first release here. Since then, stabby has grown a bit, and I feel that it's now ready to spread its wings wide with a 1.0 release!

As a reminder, stabby is a stable ABI for Rust that supports compact sum-types (enums with niche optimizations), multi-trait objects, closures and futures... All packaged inside a library that builds with any version of Rust that supports GATs!

What's new in stabby?

  • Most importantly, the stabby type representation is now specified:
    \t- You can now actually read how stabby represents your types.
    \t- You can even implement that representation in your language of choice, and be able to interract with types defined in Rust by stabby. If I ever get brave enough, I might try to implement stabby for C++, but I make no promises.
    \t- stabby's code has been validated to actually use that representation.
  • Futures have gotten faster, as they no longer allocate unless you clone the Waker in the future's implementation.
  • dyn A + B can now be cast into dyn A, another feature of stabby that rustc hasn't stabilized yet! \o/
  • stabby::Any is now a thing, and it works across the FFI boundary!
  • stabby now helps you with imports and exports, with two strategies:
    \t- #[stabby::export] requires your function signature to be IStable, and will export the symbol itself; but also a helper function that allows comparing the shared library's vision of the involved types with the importer's vision.
    \t\t- #[stabby::import] can be placed on extern blocks to make all imports in them check that the host and guest have the same vision of types at first use of the imported symbols.
    \t\t- StabbyLibrary::get_stabbied can be used on libloading::Library to do the same checks when loading a symbol.
    \t- #[stabby::export(canaries)] can be used on any function (including ABI-unstable ones), and will export additional symbols that encode some parameters that may affect the ABI.
    \t\t- #[stabby::import(canaries = "")] will declare the symbol, as well as the same additional symbols. If the parameters have changed between the two compilations, there's a chance that ABI will be broken: the symbols would then be different from the shared library, causing linkage to fail.
    \t\t- StabbyLibrary::get_canaried can be used on libloading::Library to do the same checks when loading a symbol.

With this, I consider stabby itself to achieve its main goals, but its equivalent of the std library is still rather small, I will now start to address this.

EDIT: The following section of the post was missing for some reason.

That's not much, isn't it?

Well, yes, but some implementation details have improved here and there. And after all, wouldn't it be problematic for a library that aims to provide stability to keep changing around?

How will you handle versioning in the future?

stabby's core mission is to provide a stability, which makes its relation with semver especially tense. I plan to version as such:

  • Only updates that do not affect the layout or invariants of any type provided by stabby are allowed to be a patch level update. For example, adding methods to an existing type, or adding new types, is patch increment.
  • Updates that break any given type's layout or invariant, but doesn't affect how stabby generates layouts (including for v-tables) are allowed to be minor level updates. For example, adding/removing fields from an existing structure, or enforcing or no longer enforcing an invariant for a given type, would be a minor increment.
  • Updates that would break ABI for code annotated by #[stabby::stabby] will only be allowed on major level updates. I don't expect these to happen, but by stating it, I hope to make my stance with regard to these potential changes clear.

What's next?

RustConf 2023! As I mentioned in the original post, I submitted a talk, and it was accepted! This will be my first major talk, and I'll be (remotely) going over the subject of ABI in general, how to use stabby, and how I hope stabby and its equivalents will only be a temporary need for the Rust ecosystem.

The recent fiasco can't be ignored, and my thoughts go to JeanHeyd whose talk I was really excited about, and I'll keep a close eye on their awesome work in making C somewhat modern (type inference, finally!).
I'm still very excited about this year's RustConf: my core interests make me particularly interested in Yoshua and Vitaly's talks, but this year's progam is lit in general!

I'm now planning on starting a crate to provide an alternative to the allocator API, with stabby support of course, and taking care that this API allows in-place initialization, which is a lack that I've seen cause some issues in embedded projects.

However, unlike stabby on which I was able to spend work-time, this library would be done entirely on my free time, so don't expect this to come out too quickly.

Zenoh's plugin system was one of the main motivators for building stabby. However, Zenoh needs me on other fronts at the moment, so stabby will have to go to the back burner for a bit. This doesn't mean stabby will become unsupported: if you want to use it, and are having a hard time, feel free to DM me to get some support. In fact, what stabby needs most right now is feedback on what types you'd like to see supported, so go for it!