Skip to content

Commit bd5a3fe

Browse files
committed
feat: mutliple prologue steps
1 parent 2e232ce commit bd5a3fe

File tree

4 files changed

+114
-56
lines changed

4 files changed

+114
-56
lines changed

src/pipelines/exec/navi.rs

Lines changed: 88 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use {
1010
core::fmt::Formatter,
1111
derive_more::{From, Into},
1212
smallvec::{SmallVec, smallvec},
13-
std::sync::Arc,
13+
std::{cmp::min, sync::Arc},
1414
};
1515

1616
/// Represents a path to a step or a nested pipeline in a pipeline.
@@ -24,9 +24,10 @@ use {
2424
#[derive(PartialEq, Eq, Clone, From, Into, Hash)]
2525
pub(crate) struct StepPath(SmallVec<[usize; 8]>);
2626

27+
const EXTRA_SECTIONS_SIZE: usize = 1024;
2728
const PROLOGUE_INDEX: usize = usize::MIN;
28-
const EPILOGUE_START_INDEX: usize = usize::MAX - 1024; // Reserve space for epilogue steps
29-
const STEP0_INDEX: usize = PROLOGUE_INDEX + 1;
29+
const STEP0_INDEX: usize = PROLOGUE_INDEX + EXTRA_SECTIONS_SIZE + 1;
30+
const EPILOGUE_START_INDEX: usize = usize::MAX - EXTRA_SECTIONS_SIZE;
3031

3132
/// Public API
3233
impl StepPath {
@@ -81,7 +82,7 @@ impl StepPath {
8182

8283
/// Returns `true` if the path is pointing to a prologue of a pipeline.
8384
pub(crate) fn is_prologue(&self) -> bool {
84-
self.leaf() == PROLOGUE_INDEX
85+
self.leaf() < STEP0_INDEX
8586
}
8687

8788
/// Returns `true` if the path is pointing to an epilogue of a pipeline.
@@ -227,30 +228,44 @@ impl StepPath {
227228
///
228229
/// None of those methods do any checks on the validity of the path.
229230
impl StepPath {
230-
/// Returns a step path that points to the prologue step.
231-
pub(in crate::pipelines) fn prologue() -> Self {
232-
Self(smallvec![PROLOGUE_INDEX])
231+
/// Returns a leaf step path pointing at a specific prologue step with the
232+
/// given index.
233+
pub(in crate::pipelines) fn prologue_step(prologue_index: usize) -> Self {
234+
Self(smallvec![min(
235+
prologue_index + PROLOGUE_INDEX,
236+
STEP0_INDEX - 1,
237+
)])
233238
}
234239

235-
/// Returns a leaf step path pointing at the first epilogue step.
236-
pub(in crate::pipelines) fn epilogue() -> Self {
237-
Self::epilogue_step(0)
240+
/// Returns a step path that points to the first prologue step.
241+
pub(in crate::pipelines) fn prologue() -> Self {
242+
Self::prologue_step(0)
238243
}
239244

240245
/// Returns a leaf step path pointing at a specific epilogue step with the
241246
/// given index.
242247
pub(in crate::pipelines) fn epilogue_step(epilogue_index: usize) -> Self {
243-
Self(smallvec![epilogue_index + EPILOGUE_START_INDEX])
248+
Self(smallvec![
249+
epilogue_index.saturating_add(EPILOGUE_START_INDEX)
250+
])
244251
}
245252

246-
/// Returns a new step path that points to the first non-prologue step.
247-
pub(in crate::pipelines) fn step0() -> Self {
248-
Self::step(0)
253+
/// Returns a leaf step path pointing at the first epilogue step.
254+
pub(in crate::pipelines) fn epilogue() -> Self {
255+
Self::epilogue_step(0)
249256
}
250257

251258
/// Returns a leaf step path pointing at a step with the given index.
252259
pub(in crate::pipelines) fn step(step_index: usize) -> Self {
253-
Self(smallvec![step_index + STEP0_INDEX])
260+
Self(smallvec![min(
261+
step_index + STEP0_INDEX,
262+
EPILOGUE_START_INDEX - 1
263+
)])
264+
}
265+
266+
/// Returns a new step path that points to the first non-prologue step.
267+
pub(in crate::pipelines) fn step0() -> Self {
268+
Self::step(0)
254269
}
255270

256271
/// Appends a new path to the current path.
@@ -280,20 +295,22 @@ impl core::fmt::Display for StepPath {
280295

281296
if let Some(&first) = iter.next() {
282297
match first {
283-
PROLOGUE_INDEX => write!(f, "p"),
298+
idx if idx < STEP0_INDEX => write!(f, "p{}", idx - PROLOGUE_INDEX),
284299
idx if idx >= EPILOGUE_START_INDEX => {
285300
write!(f, "e{}", idx - EPILOGUE_START_INDEX)
286301
}
287-
index => write!(f, "{index}"),
302+
idx => write!(f, "{}", idx - STEP0_INDEX),
288303
}?;
289304

290305
for &index in iter {
291306
match index {
292-
PROLOGUE_INDEX => write!(f, "_p"),
307+
idx if idx < STEP0_INDEX => {
308+
write!(f, "_p{}", idx - PROLOGUE_INDEX)
309+
}
293310
idx if idx >= EPILOGUE_START_INDEX => {
294311
write!(f, "_e{}", idx - EPILOGUE_START_INDEX)
295312
}
296-
index => write!(f, "_{index}"),
313+
idx => write!(f, "_{}", idx - STEP0_INDEX),
297314
}?;
298315
}
299316
}
@@ -325,7 +342,7 @@ impl<'a, P: Platform> StepNavigator<'a, P> {
325342
/// Given a pipeline, returns a navigator that points at the first executable
326343
/// item in the pipeline.
327344
///
328-
/// In pipelines with a prologue, this will point to the prologue step.
345+
/// In pipelines with a prologue, this will point to the first prologue step.
329346
/// In pipelines without a prologue, this will point to the first step.
330347
/// In pipelines with no steps, but with an epilogue, this will point to the
331348
/// first epilogue step.
@@ -340,8 +357,8 @@ impl<'a, P: Platform> StepNavigator<'a, P> {
340357
}
341358

342359
// pipeline has a prologue, return it.
343-
if pipeline.prologue().is_some() {
344-
return Some(Self(StepPath::prologue(), vec![pipeline]));
360+
if !pipeline.prologue().is_empty() {
361+
return Self(StepPath::prologue(), vec![pipeline]).enter();
345362
}
346363

347364
// pipeline has no prologue
@@ -369,6 +386,11 @@ impl<'a, P: Platform> StepNavigator<'a, P> {
369386
if self.is_prologue() {
370387
enclosing_pipeline
371388
.prologue()
389+
.get(
390+
step_index
391+
.checked_sub(PROLOGUE_INDEX)
392+
.expect("step index should be >= prologue index"),
393+
)
372394
.expect("Step path points to a non-existing prologue")
373395
} else if self.is_epilogue() {
374396
enclosing_pipeline
@@ -419,9 +441,10 @@ impl<'a, P: Platform> StepNavigator<'a, P> {
419441
///
420442
/// Returns `None` if there are no more steps to execute in the pipeline.
421443
pub(crate) fn next_ok(self) -> Option<Self> {
444+
let enclosing_pipeline = self.pipeline();
445+
422446
if self.is_epilogue() {
423447
// we are in an epilogue step, check if there are more epilogue steps
424-
let enclosing_pipeline = self.pipeline();
425448
let epilogue_index = self
426449
.0
427450
.leaf()
@@ -437,12 +460,22 @@ impl<'a, P: Platform> StepNavigator<'a, P> {
437460
}
438461

439462
if self.is_prologue() {
440-
// start looping (if possible)
463+
// we are in a prologue step, check if there are more prologue steps
464+
let prologue_index = self
465+
.0
466+
.leaf()
467+
.checked_sub(PROLOGUE_INDEX)
468+
.expect("invalid prologue step index in the step path");
469+
470+
if prologue_index + 1 < enclosing_pipeline.prologue.len() {
471+
// there are more prologue step, go to the next one
472+
return Self(self.0.increment_leaf(), self.1.clone()).enter();
473+
}
474+
475+
// this is the last prologue step, enter step section
441476
return self.after_prologue();
442477
}
443478

444-
let enclosing_pipeline = self.pipeline();
445-
446479
// we are in a regular step.
447480
assert!(
448481
!enclosing_pipeline.steps().is_empty(),
@@ -480,7 +513,8 @@ impl<'a, P: Platform> StepNavigator<'a, P> {
480513
///
481514
/// Returns `None` if there are no more steps to execute in the pipeline.
482515
pub(crate) fn next_break(self) -> Option<Self> {
483-
if self.is_epilogue() {
516+
// breaking in prologue or epilogue directly stop pipeline execution
517+
if self.is_epilogue() || self.is_prologue() {
484518
// the loop is over.
485519
return self.next_in_parent();
486520
}
@@ -553,7 +587,7 @@ impl<P: Platform> StepNavigator<'_, P> {
553587

554588
if path.is_prologue() {
555589
assert!(
556-
enclosing_pipeline.prologue().is_some(),
590+
!enclosing_pipeline.prologue().is_empty(),
557591
"path is prologue, but the enclosing pipeline has none",
558592
);
559593
// if we are in a prologue, we can just return ourselves.
@@ -673,6 +707,7 @@ mod test {
673707

674708
fake_step!(Prologue1);
675709
fake_step!(Prologue2);
710+
fake_step!(Prologue3);
676711

677712
fake_step!(Step1);
678713
fake_step!(Step2);
@@ -704,6 +739,7 @@ mod test {
704739
(StepX, StepY, StepZ)
705740
.with_name("nested1.1")
706741
.with_prologue(Prologue2)
742+
.with_prologue(Prologue3)
707743
.with_epilogue(Epilogue2),
708744
)
709745
.with_step(StepC)
@@ -724,6 +760,10 @@ mod test {
724760
self.concat(StepPath::prologue())
725761
}
726762

763+
fn append_prologue_step(self, step_index: usize) -> Self {
764+
self.concat(StepPath::prologue_step(step_index))
765+
}
766+
727767
fn append_epilogue(self) -> Self {
728768
self.concat(StepPath::epilogue())
729769
}
@@ -787,7 +827,7 @@ mod test {
787827
vec!["one", "two"]
788828
);
789829

790-
// one nested step with prologue
830+
// one nested step with a one-step prologue
791831
assert_entrypoint!(
792832
Pipeline::<Ethereum>::named("one").with_pipeline(
793833
Loop,
@@ -905,7 +945,16 @@ mod test {
905945
assert_eq!(cursor.0, StepPath::step(2).append_step(0));
906946

907947
let cursor = cursor.next_ok().unwrap();
908-
assert_eq!(cursor.0, StepPath::step(2).append_step(1).append_prologue());
948+
assert_eq!(
949+
cursor.0,
950+
StepPath::step(2).append_step(1).append_prologue_step(0)
951+
);
952+
953+
let cursor = cursor.next_ok().unwrap();
954+
assert_eq!(
955+
cursor.0,
956+
StepPath::step(2).append_step(1).append_prologue_step(1)
957+
);
909958

910959
let cursor = cursor.next_ok().unwrap();
911960
assert_eq!(cursor.0, StepPath::step(2).append_step(1).append_step(0));
@@ -947,12 +996,12 @@ mod test {
947996
assert_eq!(cursor.0, StepPath::step(2).append_step(0));
948997

949998
let cursor = cursor.next_ok().unwrap();
950-
assert_eq!(cursor.0, StepPath::step(2).append_step(1).append_prologue());
999+
assert_eq!(
1000+
cursor.0,
1001+
StepPath::step(2).append_step(1).append_prologue_step(0)
1002+
);
9511003

9521004
let cursor = cursor.next_break().unwrap();
953-
assert_eq!(cursor.0, StepPath::step(2).append_step(1).append_epilogue());
954-
955-
let cursor = cursor.next_ok().unwrap();
9561005
assert_eq!(cursor.0, StepPath::step(2).append_step(2));
9571006

9581007
let cursor = cursor.next_break().unwrap();
@@ -998,12 +1047,15 @@ mod test {
9981047
assert_eq!(navigator.instance().name(), cursor.instance().name());
9991048

10001049
let cursor = cursor.next_ok().unwrap();
1001-
assert_eq!(cursor.0, StepPath::step(2).append_step(1).append_prologue());
1050+
assert_eq!(
1051+
cursor.0,
1052+
StepPath::step(2).append_step(1).append_prologue_step(0)
1053+
);
10021054
let navigator = cursor.0.navigator(&pipeline).unwrap();
10031055
assert_eq!(navigator.1.len(), cursor.1.len());
10041056
assert_eq!(
10051057
navigator.0,
1006-
StepPath::step(2).append_step(1).append_prologue()
1058+
StepPath::step(2).append_step(1).append_prologue_step(0)
10071059
);
10081060
assert_eq!(navigator.instance().name(), cursor.instance().name());
10091061

src/pipelines/iter.rs

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ struct Frame<'a, P: Platform> {
1010
pipeline: &'a Pipeline<P>,
1111
path: StepPath,
1212
next_ix: usize,
13-
yielded_prologue: bool,
13+
prologue_ix: usize,
1414
epilogue_ix: usize,
1515
}
1616

@@ -21,7 +21,7 @@ impl<'a, P: Platform> StepPathIter<'a, P> {
2121
pipeline,
2222
next_ix: 0,
2323
path: StepPath::empty(),
24-
yielded_prologue: false,
24+
prologue_ix: 0,
2525
epilogue_ix: 0,
2626
}],
2727
}
@@ -35,10 +35,11 @@ impl<P: Platform> Iterator for StepPathIter<'_, P> {
3535
loop {
3636
let frame = self.stack.last_mut()?;
3737

38-
// Yield prologue once, if present.
39-
if !frame.yielded_prologue && frame.pipeline.prologue.is_some() {
40-
frame.yielded_prologue = true;
41-
return Some(frame.path.clone().concat(StepPath::prologue()));
38+
// Walk prologue steps
39+
if frame.prologue_ix < frame.pipeline.prologue.len() {
40+
let ix = frame.prologue_ix;
41+
frame.prologue_ix += 1;
42+
return Some(frame.path.clone().concat(StepPath::prologue_step(ix)));
4243
}
4344

4445
// Walk steps; descend into nested pipelines.
@@ -55,15 +56,15 @@ impl<P: Platform> Iterator for StepPathIter<'_, P> {
5556
pipeline: nested,
5657
path: next_path,
5758
next_ix: 0,
58-
yielded_prologue: false,
59+
prologue_ix: 0,
5960
epilogue_ix: 0,
6061
});
6162
continue;
6263
}
6364
}
6465
}
6566

66-
// Walk epilogue steps/pipelines; descend into nested pipelines.
67+
// Walk epilogue steps
6768
if frame.epilogue_ix < frame.pipeline.epilogue.len() {
6869
let ix = frame.epilogue_ix;
6970
frame.epilogue_ix += 1;
@@ -81,9 +82,9 @@ mod tests {
8182
use {super::*, crate::test_utils::fake_step};
8283

8384
fake_step!(PrologueOne);
84-
fake_step!(EpilogueOne);
85-
8685
fake_step!(PrologueTwo);
86+
87+
fake_step!(EpilogueOne);
8788
fake_step!(EpilogueTwo);
8889

8990
fake_step!(Step1);
@@ -98,12 +99,14 @@ mod tests {
9899
fn visits_all_steps_flat() {
99100
let pipeline = Pipeline::<Optimism>::default()
100101
.with_prologue(PrologueOne)
102+
.with_prologue(PrologueTwo)
101103
.with_step(Step1)
102104
.with_step(Step2)
103105
.with_step(Step3)
104-
.with_epilogue(EpilogueOne);
106+
.with_epilogue(EpilogueOne)
107+
.with_epilogue(EpilogueTwo);
105108

106-
let expected = vec!["p", "1", "2", "3", "e0"];
109+
let expected = vec!["p0", "p1", "0", "1", "2", "e0", "e1"];
107110
let actual = pipeline
108111
.iter_steps()
109112
.map(|step| step.to_string())
@@ -126,7 +129,7 @@ mod tests {
126129
.with_epilogue(EpilogueOne);
127130

128131
let expected = vec![
129-
"p", "1_p", "1_1", "1_2_1", "1_2_2", "1_2_3", "1_2_e0", "1_3", "e0",
132+
"p0", "0_p0", "0_0", "0_1_0", "0_1_1", "0_1_2", "0_1_e0", "0_2", "e0",
130133
];
131134

132135
let actual = pipeline

0 commit comments

Comments
 (0)