8 releases
new 0.3.0 | Dec 9, 2024 |
---|---|
0.2.0 | Nov 13, 2024 |
0.1.6 | Nov 7, 2024 |
0.1.4 | Oct 30, 2024 |
0.1.0 | Oct 11, 2023 |
#440 in Game dev
463 downloads per month
12KB
Intrepid
Intrepid is a magic handler kit where most of the boilerplate work is already done. For cases where you'd like to get the ergonomics of Bevy or Actix-Web, but for your own stuff.
TODO
- Demote pattern as a central concern, put it into routing and extract packages. It's mostly gone now anyway, because of
path_tree
. It's mostly just a matter of clean-up. - Closer integration between actions and tower services, so that more Layers can be put into place on actions and systems. Right now, the impediment is that actions and systems have points where they're "not quite ready" to be used as a service, and unfortunately we want them to be configured as a service at that point. In other words, there probably needs to be some kind of concept introduced that lets unrealized actions/systems store layers for later. Maybe by giving them an idea of the kind of service they'll "eventually" be, along with a place to store a
Layer
impl that will work when that day comes?
About the current state of handlers
Handler might be "SimpleHandler", or in other words, it results in an ecosystem with a Frame, State dependency. The "canon handler" could be better designed as a wrapper trait that adds two specific trait dependencies.
- The
ExtractFrame
trait, which describes a future that resolves to an implementing type. The extract frame approach lets us add asynchrony to this portion, and it lets us change(Frame, State)
into a form where state could be hypothetically extracted from a frame context, for exampleFrameContext<State>
. - The
IntoFrame
trait, which describes a response type that is guaranteed to always resolve to something that fits the expectations of the surrounding ecosystem. Right now that guarantee isn't there.
Together both of these traits could also improve documentation / error messaging.
Finally, if we have an async fn(impl ExtractFrame) -> impl IntoFrame
type of any sort, we know we can do the Stream / Sink guarantee in outer levels with no additional work, because we'll know if the State
of our FrameContext<State>
contains anything that implements our repo traits.
More on a second trait layer
This might be the key to getting our composition boundaries in shape. Right now we need to know that something can turn into a Frame
in the innermost layer, and then as we progress to more concrete layers, we have to just say "ok give me a Frame
" in our generic notation or else shit gets cray.
The key to getting these layers into a more generic umbrella might be to create a secondary layer of traits, as outlined above with ExtractFrame
and IntoFrame
.
Even more about it
There's undoubtedly an opportunity to create a different function signature for handlers. Right now we have the ability to model out logic like this, and it's very powerful:
async fn(data, state) -> data
But, this might be more powerful:
async fn(data, state) -> (data, effects)
In other words, "things for the program to do", right now, can happen in the function, and "things to delegate to the program for whenever", that can go into effects.
This isn't a pressing need! Because right now, state
can represent the application machinery, and it's highly customizable in that regard. So, for example, application-modeled persistence and that kind of side-effect are already something we can register there.
Dependencies
~59MB
~1M SLoC