-
-
Notifications
You must be signed in to change notification settings - Fork 34
Description
Hi, Bon is my favorite crate and I'm using it as the backbone for a complex pipeline internal framework.
In essence, my pipeline works like this:
pipeline
.pass(the_first_step)
.pass(another_step)
.pass(some_other_step)
.pass(the_last_step)Each step of the pipeline is (simplified) implemented like this:
pub async fn the_first_step<S>(
Payload(id): Payload,
PgConn(pg_conn): PgConn,
State(builder): State<NewDbRowBuilder<S>>,
) -> Result<NewDbRowBuilder<SetTheFirstStepValue<S>>, crate::Error>
where
S: new_db_row_builder::State,
S::TheFirstStepValue: IsUnset,
{
// some work that connects to api, db, etc, and produces a value
Ok(builder.the_first_step_value(my_awesome_value_i_fetched))
}The types of the pipeline enforce that the state produced by a prior pass must be fed into the pass under it, so you can't accidentally order anything wrong. I love using Bon to back this pipeline system and allow me to make each pass specify what the conditions of its state should be.
Where I am struggling is that sometimes I run into a weird, limiting situation.
I have one step in my pipeline that scrapes some information off of a user in my DB, processes it, then sets it in the builder (because this value must go in the row that's being built). Then, in another pass of the pipeline, I must read processed data out and use it to compute another value that also goes on my row. Given the current implementation of Bon (while following the rules and not directly implementing unsafe methods on generated code), I have three solutions:
- Take this processed value, clone it and set it into the state, then return a tuple of the state and the cloned value. This is bad to me because the passes of my pipeline become much less generic as they now must take a tuple of the built state and any previously obtained values and drill them through the entire way
- Do what I'm doing currently, and maintain a cache that passes can use to set values and retrieve them later. This works (and is fairly generic), but I lose the ability to safely do the guards like
IsSetbecause this cache has to be completely detached frombon - Use
builder(field)on these fields I want to cache. This also works, but it has the same problem as before where I lose the ability to do guards on the passes which is what I love so much about bon.
I noticed in 3.1.1 you removed the non-determinism of generated privates. After seeing this, being able to add methods that take in &self and return a reference to a value in the builder state would be incredible and make my pipeline work exactly how I want it to. This long winded context finally leads to my question (the one in the title)...
How fundamentally unsafe is this? Taking a look at the expanded macro from builder everything I can see indicates that adding read only accessor methods that do not move out of the tuple or clone the data would be completely safe, but I figured it would be well worth opening an issue for this because this will be running in production code where a mistake like this will not be acceptable.
Thank you!
A note for the community from the maintainers
Please vote on this issue by adding a 👍 reaction to help the maintainers with prioritizing it. You may add a comment describing your real use case related to this issue for us to better understand the problem domain.