Skip to content

Conversation

@julio4
Copy link
Collaborator

@julio4 julio4 commented Nov 10, 2025

The idea is to be able to defines combinator step: a step that is combined out of multiple underlying steps.

I introduce a CombinatorStep that is a subtrait of Step, that takes a impl Into<Vec<Arc<StepInstance<P>>>> to allows for different syntaxic sugar later :)

Then a combinator macro is defined to encapsulate base logic of creating a combinator step by:

  • defining a struct with a vector to hold step instances
  • auto implementation of CombinatorStep
  • implementation of an append method that push the given step in the steps vec, but with the option to provide a different name (like and with atomic, or with any etc..)
  • implementation of steps() function to get a slice of the step instances

The generated struct still needs to implement manually Step. This is enforced at compile time because CombinatorStep impl requires Step impl.

Other points:

  • needs to clone contexts for each sub-steps
  • removed Sync bounds on some futures, that seemed unnecessary

Included as well a combinator step implementation for Atomic (related work was done in #59 but moved here)

Towards #31

Copy link
Collaborator

@karim-agha karim-agha left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

None of those are strong opinions, just discussion starters.

Comment on lines 138 to 141
let mut composite = CompositeStep::<P, _>::new(TryAllMode);
composite.append_step(AlwaysOkStep);
composite.append_step(AlwaysOkStep);
composite.append_step(AlwaysOkStep);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest that we tweak the DevEx here a little bit and enable the following syntax:

let pipeline = Pipeline::default()
  .with_prologue(All((Step1, Step2, Step3))
  .step(Step4)
  .with_epilogue(Any((Step5, Step6)));

This is how this syntax is implemented for constructing pipelines:

rblib/src/pipelines/mod.rs

Lines 226 to 269 in d52ed99

pub trait IntoPipeline<P: Platform, Marker = ()> {
#[track_caller]
fn into_pipeline(self) -> Pipeline<P>;
}
impl<P: Platform, F: FnOnce(Pipeline<P>) -> Pipeline<P>>
IntoPipeline<P, Variant<0>> for F
{
#[track_caller]
fn into_pipeline(self) -> Pipeline<P> {
self(Pipeline::<P>::default())
}
}
impl<P: Platform> IntoPipeline<P, Variant<0>> for Pipeline<P> {
#[track_caller]
fn into_pipeline(self) -> Pipeline<P> {
self
}
}
impl<P: Platform, S0: Step<P>> IntoPipeline<P, Variant<0>> for (S0,) {
#[track_caller]
fn into_pipeline(self) -> Pipeline<P> {
Pipeline::default().with_step(self.0)
}
}
impl<P: Platform, S0: Step<P>> IntoPipeline<P, Variant<1>> for S0 {
#[track_caller]
fn into_pipeline(self) -> Pipeline<P> {
Pipeline::default().with_step(self)
}
}
// Generate implementations for tuples of steps up to 32 elements
#[cfg(not(feature = "long-pipelines-syntax"))]
impl_into_pipeline_steps!(32);
// Generate implementations for tuples of steps up to 512 elements.
// This is opt-in through a compile-time feature flag and in practice
// should never be needed, but it's here just in case.
#[cfg(feature = "long-pipelines-syntax")]
impl_into_pipeline_steps!(128);

Not a blocker, but a very nice to have to preserve consistency with the overall syntax.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also had this in mind, but to keep things scoped what about not adding it directly and just relying on combinator implementation with macro?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added the trait CombinatorStep that takes steps: impl Into<Steps<P>>, that should allows for adding this syntax

@julio4 julio4 changed the title feat: CompositeStep feat: Combinator Steps Nov 11, 2025
@julio4 julio4 changed the title feat: Combinator Steps feat: Combinator Steps + Atomic Nov 11, 2025
};
}

combinator!(Atomic, and);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

combinator! is a private macro that implements CombinatorStep with a struct with a vec of step instances.

One nice thing is that because CombinatorStep has Step as a supertrait, this force implementation of Step for the combinator step.

Comment on lines 101 to 115
if ctx.deadline_reached() {
return ControlFlow::Break(initial);
}

match step.step(current, ctx.clone()).await {
ControlFlow::Ok(next) => current = next,
_ => return ControlFlow::Ok(initial),
}
}

if ctx.deadline_reached() {
ControlFlow::Break(initial)
} else {
ControlFlow::Ok(current)
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following previous discussion, I changed to return Ok(initial) on Fail/Break.

What about deadline reached?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the deadline is reached before all steps complete successfully then we don't have atomic result semantics and I would return the initial payload.

@julio4 julio4 requested a review from karim-agha November 11, 2025 13:25
Comment on lines 101 to 115
if ctx.deadline_reached() {
return ControlFlow::Break(initial);
}

match step.step(current, ctx.clone()).await {
ControlFlow::Ok(next) => current = next,
_ => return ControlFlow::Ok(initial),
}
}

if ctx.deadline_reached() {
ControlFlow::Break(initial)
} else {
ControlFlow::Ok(current)
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the deadline is reached before all steps complete successfully then we don't have atomic result semantics and I would return the initial payload.

@julio4 julio4 merged commit 8faa758 into flashbots:main Nov 11, 2025
7 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants