// Deterministic forwarding of one completed normal result through a sealed,
// non-empty sequence of direct-return helper calls. The pipeline has no
// completion policy and performs no guest or lifecycle effects.
///|
priv struct DispatchResultPipelineCalleeToken(Value)
///|
priv struct DispatchResultPipelineStage {
request : DispatchCallRequest
callee_token : DispatchResultPipelineCalleeToken
result_argument_index : Int
}
///|
fn validate_dispatch_result_pipeline_stage(
request~ : DispatchCallRequest,
callee_token~ : DispatchResultPipelineCalleeToken,
result_argument_index~ : Int,
) -> DispatchResultPipelineStage? {
guard result_argument_index >= 0 &&
result_argument_index < request.args.length() else {
return None
}
Some({
request: DispatchCallRequest(
callee=request.callee,
this_value=request.this_value,
args=request.args,
loc=request.loc,
),
callee_token,
result_argument_index,
})
}
///|
fn snapshot_dispatch_result_pipeline_stage(
stage : DispatchResultPipelineStage,
) -> DispatchResultPipelineStage {
{
request: DispatchCallRequest(
callee=stage.request.callee,
this_value=stage.request.this_value,
args=stage.request.args,
loc=stage.request.loc,
),
callee_token: stage.callee_token,
result_argument_index: stage.result_argument_index,
}
}
///|
priv struct DispatchResultPipeline {
stages : Array[DispatchResultPipelineStage]
}
///|
fn validate_dispatch_result_pipeline(
stages~ : Array[DispatchResultPipelineStage],
) -> DispatchResultPipeline? {
guard !stages.is_empty() else { return None }
Some({ stages: stages.map(snapshot_dispatch_result_pipeline_stage) })
}
///|
fn snapshot_dispatch_result_pipeline(
pipeline : DispatchResultPipeline,
) -> DispatchResultPipeline {
{ stages: pipeline.stages.map(snapshot_dispatch_result_pipeline_stage) }
}
///|
fn DispatchResultPipeline::start(
self : DispatchResultPipeline,
) -> DispatchResultPipelineCursor {
{ pipeline: snapshot_dispatch_result_pipeline(self), next_index: 0 }
}
///|
priv struct DispatchResultPipelineCursor {
pipeline : DispatchResultPipeline
next_index : Int
}
///|
fn snapshot_dispatch_result_pipeline_cursor(
cursor : DispatchResultPipelineCursor,
) -> DispatchResultPipelineCursor {
{
pipeline: snapshot_dispatch_result_pipeline(cursor.pipeline),
next_index: cursor.next_index,
}
}
///|
priv enum DispatchResultPipelineDecision {
DispatchResultPipelineSuspend(
DispatchCallRequest,
DispatchResultPipelineCursor
)
DispatchResultPipelineComplete(Value)
}
///|
fn dispatch_result_pipeline_callee_matches(
token : DispatchResultPipelineCalleeToken,
callee : Value,
) -> Bool {
same_value(token.0, callee)
}
///|
fn dispatch_result_pipeline_transition(
cursor : DispatchResultPipelineCursor,
previous_result : Value,
) -> DispatchResultPipelineDecision raise InvalidDispatchTransition {
let pipeline = cursor.pipeline
guard cursor.next_index >= 0 && cursor.next_index <= pipeline.stages.length() else {
invalid_dispatch_transition("result pipeline cursor is outside its stages")
}
guard cursor.next_index < pipeline.stages.length() else {
return DispatchResultPipelineComplete(previous_result)
}
let stage = pipeline.stages[cursor.next_index]
guard dispatch_result_pipeline_callee_matches(
stage.callee_token,
stage.request.callee,
) else {
invalid_dispatch_transition("result pipeline stage callee token drifted")
}
guard stage.result_argument_index >= 0 &&
stage.result_argument_index < stage.request.args.length() else {
invalid_dispatch_transition(
"result pipeline carried-result index is outside request args",
)
}
let args = stage.request.args.copy()
args[stage.result_argument_index] = previous_result
let request = DispatchCallRequest(
callee=stage.request.callee,
this_value=stage.request.this_value,
args~,
loc=stage.request.loc,
)
let next_cursor : DispatchResultPipelineCursor = {
pipeline: snapshot_dispatch_result_pipeline(pipeline),
next_index: cursor.next_index + 1,
}
DispatchResultPipelineSuspend(request, next_cursor)
}