Replies: 5 comments
-
Hi there @anelson ! Thank you for taking the time to start this discussion much appreciate due to the fact that I was considering other alternatives for the current plugins implementation. The current plugin system uses a simple macro to generate a C-compatible constructor for plugins, but it does not inherently solve the ABI stability issue with trait objects. The approach relies on compiling plugins and the main application with the same Rust toolchain, which mitigates but does not completely eliminate potential undefined behavior due to trait vtable instability and this put some of the compatibility burdens on the end user. |
Beta Was this translation helpful? Give feedback.
-
The approach of hosting a WASM runtime with serialization into and out of the plugin is the only thing I've found that's sufficiently flexible and reliable while being reasonably low-effort, but it comes with significant limitations particularly around performance and flexibility which is why I was hopeful that maybe you'd found some secret handshake to host native Rust plugins w/o the downsides :) A thousand years ago when I was starting my career, Windows had a cross-language object-oriented component mechanism called COM, which for a while was The Way in Windows to extend Windows components like Explorer and tools like Word with third-party code. One of the many reasons why it was such a nightmare was that it had to solve the problem of how to free memory in the host that was allocated in a plugin, or vice versa. Even if the ABI issue were solved, you'd still have memory management to worry about, and COM's solution was incredibly easy to mess up, leading to heap corruption and UB. Sadly I don't think solving this in a general way while keeping all of the Rust ergonomics and affordances is likely, so WASM seems like the way forward. Perhaps over time WASI will mature and it will be possible to meaningfully interact with host hardware from within WASM. For now, as far as I'm aware the state of the art in WASM plugins in a Rust project is Zellij plugins, and no offense to the developers of Zellij but that is damning with faint praise ;) One other approach I have toyed with is hosting the Lua runtime in Rust, exposing Rust functions to Lua for performance-critical tasks. This is by no means a silver bullet, it comes with significant downsides and is labor-intensive, but in my opinion it ends up putting less burden on the plugin authors (assuming they like writing Lua code). |
Beta Was this translation helpful? Give feedback.
-
Hey there @anelson ! Just wanted to let you know I've shipped |
Beta Was this translation helpful? Give feedback.
-
Nice! Clever workaround! We use Protobuf extensively in my day job, the Rust support via I notice you're using a I like this better than WASM, especially for such a low-level tool like this. It would piss me off if I run |
Beta Was this translation helpful? Give feedback.
-
Thanks for the fantastic feedback @anelson! I like your suggestion about generating protobuf bindings in CI and including them in source control - that's definitely going to make things smoother for plugin developers. I'll work on implementing this soon to hide all those protobuf complexities under the hood. And yeah, really glad we went this route instead of WASM for keeping things fast and flexible, while WASM is a neat concept, those cold starts would make lla painfully slow. |
Beta Was this translation helpful? Give feedback.
-
I saw this project on the Console mailing list, and was intrigued by the fact that you have a Rust plugin model that appears not to use WASM. So I looked into how you did it and see that this is the key:
https://github.com/triyanox/lla/blob/0275f0efb4e02ef695a105128c37e1dc5a7f3d07/lla_plugin_interface/src/lib.rs#L41-L49
I'm curious, how did you make this stable across Rust compiler versions? Trait vtables specifically and the Rust ABI in general is not stable across compiler versions, so unless all plugins as well as the main executable are all compiled with exactly the same Rust compiler version on the same platform, making calls into that
dyn Trait
pointer can cause UB. Am I missing some secret sauce?Beta Was this translation helpful? Give feedback.
All reactions