// Dispatch paths (src/path.js compact()/toTransactionPath() over paths that
// carry DynStep markers and per-step component provenance).
///|
pub fn DispatchPath::new(items? : Array[DispatchStep]) -> DispatchPath {
match items {
Some(i) => { items: i }
None => { items: [] }
}
}
///|
pub fn DispatchPath::of_steps(steps : Array[Step]) -> DispatchPath {
{ items: steps.map(s => Plain(step=s, origin=None)) }
}
///|
pub fn DispatchPath::concat(
self : DispatchPath,
steps : Array[Step],
) -> DispatchPath {
let items = self.items.copy()
for s in steps {
items.push(Plain(step=s, origin=None))
}
{ items, }
}
///|
pub fn DispatchPath::pop_step(self : DispatchPath) -> DispatchPath {
let n = self.items.length()
if n == 0 {
self
} else {
{ items: self.items[0:n - 1].to_owned() }
}
}
///|
pub fn DispatchPath::compact(self : DispatchPath) -> DispatchPath {
let items : Array[DispatchStep] = []
for item in self.items {
match item {
Plain(step~, origin~) =>
match step_to_abstract(step) {
Some(s) => items.push(Plain(step=s, origin~))
None => () // frame-only: dropped
}
_ => items.push(item) // Dyn markers survive: bubbling visits them
}
}
{ items, }
}
///|
/// The steps a Dyn marker splices into the transaction path in place of the
/// dropped interior span (JS DynStep/DynEachStep.teleportSteps).
fn teleport_steps(item : DispatchStep) -> Array[Step] {
match item {
Plain(..) => []
Dyn(steps~, key=None, ..) => steps
// Iterated: the last field access becomes a keyed one.
Dyn(steps~, key=Some(key), ..) =>
match steps {
[.. init, FieldStep(f)] => {
let out = init.to_owned()
out.push(SeqStep(field=f, key~))
out
}
// A seq-access dynamic (`.a[.b]`) cannot address an iterated item; a
// key-only step does not exist. Splice unchanged rather than build a
// broken step (JS warns here).
_ => steps
}
}
}
///|
pub fn DispatchPath::to_transaction_path(self : DispatchPath) -> Path {
let out : Array[(Step, Int?)] = []
for item in self.items {
match item {
Plain(step~, origin~) => out.push((step, origin))
Dyn(producer~, interior~, ..) => {
// rewind the steps contributed by components interior to the
// producer..consumer span — the data does not live under them
while out is [.., (_, Some(cid))] && interior.contains(cid) {
let _ = out.pop()
}
for ts in teleport_steps(item) {
out.push((ts, Some(producer)))
}
}
}
}
{ steps: out.map(p => p.0) }
}