So if you correctly abstract business logic from peripheral code, you can do most of your development without ever uploading to target.
I find that a lot of my development time is actually spent on lower-level tasks—like writing custom string operations—since we don't have the rich standard libraries of a host environment.
This is exactly where an emulator really shines for me. It enables a "device-less" workflow where I can work through those low-level details on a sofa at a cafe without needing to bring the physical hardware along just to verify the behavior.
Same for UART bridge - Have a look on STM32L403 implementation in QEMU which I believe does implement UART as well. And ADC and other peripherals.
And regarding autosnapshot, that's can be done via GDB as well - save RAM + registers and then load them back.