jkelleyrtp 6 hours ago

Creator here - haven't had a chance to write up a blog post yet! Stay tuned.

The gist of it is that we intercept the Rust linking phase and then drive `rustc` manually. There's some diffing logic that compares assembly between compiles and then a linking phase where we patch symbols against the running process. Works across macOS, Windows, Linux, iOS, Android, and WASM. On my m4 I can get 130ms compile-patch times, quite wicked stuff.

We handle the hard parts that the traditional dylib-reloading doesn't including TLS, statics, constructors, etc.

I've been posting demos of it to our twitter page (yes twitter, sorry...)

- With bevy: https://x.com/dioxuslabs/status/1924762773734511035

- On iOS: https://x.com/dioxuslabs/status/1920184030173278608

- Frontend + backend (axum): https://x.com/dioxuslabs/status/1913353712552251860

- Ratatui (tui apps): https://x.com/dioxuslabs/status/1899539430173786505

Our unfinished release notes are here:

https://github.com/DioxusLabs/dioxus/releases/tag/v0.7.0-alp...

More details to come!

  • 1oooqooq 4 hours ago

    can't access the xitter posts... is the axum part using the whole of dioxus or bare axum + code reloading?

    • jkelleyrtp 4 hours ago

      There's a custom `axum::serve` equivalent we built that wraps the router construction in a hot-patchable function. When the patches are loaded, we reset the TCP connections.

      It's a little specific to how dioxus uses axum today, but we plan to release an axum-only integration in the future.

cchance 23 minutes ago

Wonder if the other web frameworks like leptos will adopt subsecond or adopt their own

modeless 5 hours ago

Interesting, but the documentation makes it sound like you have to preemptively wrap all the code you think you might want to change in a special wrapper "call" function. If true that makes this a lot less appealing than existing solutions for other languages that can modify any function without special annotations.

  • jkelleyrtp 4 hours ago

    You basically need to wrap your program's `tick()` function. Otherwise you might be in the middle of malloc, hot-patch, and your struct's layout and alignment changes, and your program crashes due to undefined behavior.

    The goal is that frameworks just bake `subsecond::current` into their `tick()` function and end-users get hot-patching for free.

    • jesse__ 2 hours ago

      How would you preempt the running program during malloc? Isn't there a well-defined reload point? Major red flags going up if your program can just change at any random point..

      Also, didn't the article say explicitly that struct layout changes aren't supported??

      • anderskaseorg 2 hours ago

        There is a well-defined reload point—it’s the `subsecond::call` wrapper around `tick()`. But the hypothetical design that you seem to have in mind where this doesn’t exist would not have a well-defined reload point, so it would need to be able to preempt your program anywhere.

        Layout changes are supported for structs that don’t persist across the well-defined reload point.

  • jesse__ 2 hours ago

    Strong agree here. The 'purity' BS of not modifying the running programs address space appears to come at the cost of significant programmer pain-in-the-ass. Having to hand-hold the library to maintain the indirection table is a hard no for me.

    Metaprogramming that maintenance burden seems like it should be relatively straight-forward, if you've written a linker already.

    • jkelleyrtp an hour ago

      The challenge is that if the program is busy in a spin loop, there's no way to preempt it and modify it. Things like malloc, spin loops, network requests, syscalls etc.

      I looked into liveplusplus a lot and their unreal integration also requires a broker to get the most out of it. If you're building a game engine and want to support struct layout and alignment changes, you'll need to do some re-instancing. Hiding a `subsecond::call` deep in the bowels of the host framework hides it from the user and lets the framework handle any complicated state management it needs during hotpatches.

      I wouldn't say it's purity - the first version of subsecond actually did do in-process modification - but after playing around with it for a while, I much preferred the light runtime integration. The dioxus integration was about 5 lines of code, so it's quite minimal.

written-beyond 2 hours ago

I really want rust dylibs to be a reality. A plugin system where a library can implement a specific versioned number of a trait and we can dynamically load in that implementation to get changed behaviour. Right now implementing anything like that requires a lot of unsafe which I'm not comfortable with.

weinzierl 6 hours ago

Very nice. For a long time I wondered who would use hotpatching but working with large Java applications made me appreciate the possibility even if it is not 100% reliable (as it is in Java).

From the docs Subsecond looks almost perfect. The only downside I found is that (if I understood correctly) you have to modify the function call in the source code of every function you want to hotpatch.

It is a bit mitigated in that the change does not cost anything in release builds, but it still is a big thing. Do I want sprinkle my code with call for every function I might potentially have to patch in a debugging session?

  • jkelleyrtp 5 hours ago

    Creator here - you only need one `subsecond::call` to hook into the runtime and it doesn't even need to be in your code - it can be inside a dependency.

    Currently Dioxus and Bevy have subsecond integration so they get automatic hot-patching without any end-user setup.

    We hope to release some general purpose adapters for axum, ratatui, egui, etc.

mmastrac 8 hours ago

I'll have to give this a shot for some of the Rust server work I'm doing. progscrape.com uses a lot of tricks to boot quickly specifically because of the edit-compile-run cycle being slow (mostly deferred loading of indexes, etc).

My current day job @ Gel has me working on a Rust socket frontend for some pretty complex code and that could also be pretty interesting.

It seems to require that you choose a good "cutover" point in your codebase, but TBH that's probably not too hard to pick. The HTTP service handler in a webserver, the socket handlers in non-web serving code, etc.

It does appear to have a limitation where it will only allow the main crate to be hotpatched. That's less than ideal, but I suppose the convenience might justify some code structure changes to allow that.

cyberax 43 minutes ago

Can we have the same for Go, pretty please?

prideout 6 hours ago

Neat but I would prefer simply using a dylib for the part of my code that I want to be reloadable.