That is what I've observed too. My impression is that people go to RTOS for libraries and dependency management, which you kinda just get out of the box with Rust, cargo and crates.io.
A lot of applications simply don't use the MPU. And then consider what you get from Rust memory safety and the reduction in overall complexity of the firmware without the RTOS.
One of the things not immediately apparent for people coming to Embassy is that you can mix and match RTIC with the Embassy HALs. So the more appropriate comparison is RTIC vs the Embassy async executors.
You might want to take a look at the embassy project for a unified stm32 HAL. The idea is that it defines the APIs per peripheral version as defined by STM (spi v1, spi v2, usart v1 etc). The advantage is that a given peripheral can be used across all stm32 families with that version. This makes maintaining a HAL and keeping a unified API much simpler.
The other part is the stm32-metapac (not specific to async) that generates the PAC for any stm32 chip.
Having distinct types for P0 and P1 is deliberate and is what is called "type state programming" in the embedded rust book [0]. The advantage is that you can prevent misconfiguration at compile time (ensuring that a given pin cannot be used in multiple places). In the Zig example, it seems to me (and I have zero knowledge of Zig, so sorry if this is inaccurate) that you can potentially introduce bugs where the same pin is used twice.
For a generic led driver, it should not use these types, but instead the trait types from the embedded_hal crate, such as "OutputPin" that is implemented by the different chip-specific HALs. There is an example of a generic led driver that uses these traits at [1].
In general I recommend everyone who wants to try out Rust on embedded to read the embedded rust book, because it clarifies a lot of the reasons and advantages of its approach.
I'll add that the AMQP 1.0 spec (supported in Rabbit using a plugin) is a peer-to-peer protocol that supports both the traditional broker use case, 'direct' p2p messaging and opens some interesting uses of message routers like Apache Qpid Dispatch Router.
For Java, have a look at vertx-proton which builds on top of proton-j and is a bit more intuitive (still not great) than proton-j for creating servers and clients. :)
I recommend looking at a standard messaging protocol like AMQP 1.0, which will allow you to implement the request-response pattern in an efficient manner without message brokers. Either “direct” client server as with HTTP , or via an intermediary such as the Apache Qpid Dispatch Router.
With the dispatch router, you can use pattern matching to specify if addresses should be routed to a broker or be routed directly to a particular service.
This is way you can get the semantics that best fits your use case.
You can also use AMQP 1.0, an ISO and OASIS standard protocol, over websockets.
It supports RPC and pub/sub semantics and has client libraries in many languages. It’s implemented by many messaging components as well as Azure Service Bus.
A lot of applications simply don't use the MPU. And then consider what you get from Rust memory safety and the reduction in overall complexity of the firmware without the RTOS.