// Dispatch paths as a stack of render continuations.
///|
pub fn DispatchPath::new(items? : Array[DispatchStep]) -> DispatchPath {
{ frames: [{ base: Path::new(), items: items.unwrap_or([]), }], }
}
///|
pub fn DispatchPath::of_steps(steps : Array[Step]) -> DispatchPath {
DispatchPath::new(items=steps.map(s => Plain(step=s, origin=None)))
}
///|
pub fn DispatchPath::concat(
self : DispatchPath,
steps : Array[Step],
) -> DispatchPath {
guard self.frames is [.. init, last] else {
return DispatchPath::of_steps(steps)
}
let items = last.items.copy()
for s in steps {
items.push(Plain(step=s, origin=None))
}
{ frames: [..init, { ..last, items, }], }
}
///|
pub fn DispatchPath::push_item(
self : DispatchPath,
item : DispatchStep,
) -> DispatchPath {
guard self.frames is [.. init, last] else {
return DispatchPath::new(items=[item])
}
let items = last.items.copy()
items.push(item)
{ frames: [..init, { ..last, items, }], }
}
///|
pub fn DispatchPath::push_frame(
self : DispatchPath,
path : Path,
) -> DispatchPath {
let frames = self.frames.copy()
frames.push({ base: path, items: [], })
{ frames, }
}
///|
pub fn DispatchPath::can_pop(self : DispatchPath) -> Bool {
match self.frames {
[.. init, last] => !last.items.is_empty() || !init.is_empty()
[] => false
}
}
///|
pub fn DispatchPath::is_root(self : DispatchPath) -> Bool {
self.to_transaction_path().steps.is_empty()
}
///|
pub fn DispatchPath::pop_step(self : DispatchPath) -> DispatchPath {
guard self.frames is [.. init, last] else { return self }
if !last.items.is_empty() {
let items = last.items[0:last.items.length() - 1].to_owned()
{ frames: [..init, { ..last, items, }], }
} else if !init.is_empty() {
{ frames: init.to_owned(), }
} else {
self
}
}
///|
pub fn DispatchPath::compact(self : DispatchPath) -> DispatchPath {
let frames : Array[DispatchFrame] = []
for frame in self.frames {
let items : Array[DispatchStep] = []
for item in frame.items {
match item {
Plain(step~, origin~) =>
match step_to_abstract(step) {
Some(s) => items.push(Plain(step=s, origin~))
None => ()
}
}
}
frames.push({ ..frame, items, })
}
{ frames, }
}
///|
pub fn DispatchPath::to_transaction_path(self : DispatchPath) -> Path {
guard self.frames is [.., frame] else { return Path::new() }
let out = frame.base.steps.copy()
for item in frame.items {
match item {
Plain(step~, ..) => out.push(step)
}
}
{ steps: out, }
}