harn_vm/vm/
callable_entry.rs1use std::sync::Arc;
2use std::time::Duration;
3
4use crate::chunk::ChunkRef;
5use crate::value::{VmError, VmValue};
6
7use super::{ScopeSpan, Vm};
8
9pub(super) enum TopLevelEntry {
10 Chunk(ChunkRef),
11 Callable {
12 bootstrap: ChunkRef,
13 has_fixture: bool,
14 args: Vec<VmValue>,
15 },
16}
17
18impl TopLevelEntry {
19 pub(super) async fn run(self, vm: &mut Vm) -> Result<VmValue, VmError> {
20 match self {
21 Self::Chunk(chunk) => vm.run_chunk(chunk).await,
22 Self::Callable {
23 bootstrap,
24 has_fixture,
25 mut args,
26 } => {
27 let value = vm.run_chunk(bootstrap).await?;
28 let target = if has_fixture {
29 let VmValue::List(callables) = value else {
30 return Err(VmError::Runtime(
31 "callable entry bootstrap did not return [fixture, target]".to_string(),
32 ));
33 };
34 let [VmValue::Closure(fixture), VmValue::Closure(target)] =
35 callables.as_slice()
36 else {
37 return Err(VmError::Runtime(
38 "callable entry bootstrap returned invalid fixture callables"
39 .to_string(),
40 ));
41 };
42 let fixture_value = vm.call_closure_pub(fixture, &[]).await?;
43 args.insert(0, fixture_value);
44 Arc::clone(target)
45 } else {
46 let VmValue::Closure(target) = value else {
47 return Err(VmError::Runtime(
48 "callable entry bootstrap did not return a callable".to_string(),
49 ));
50 };
51 target
52 };
53 vm.call_closure_pub(&target, &args).await
54 }
55 }
56 }
57}
58
59impl Vm {
60 pub async fn execute_callable_entry_with_timeout(
68 &mut self,
69 entry: &crate::CompiledCallableEntry,
70 args: &[VmValue],
71 timeout: Duration,
72 ) -> Result<VmValue, VmError> {
73 self.execute_top_level_with_timeout(
74 TopLevelEntry::Callable {
75 bootstrap: Arc::new(entry.bootstrap.clone()),
76 has_fixture: entry.has_fixture,
77 args: args.to_vec(),
78 },
79 timeout,
80 )
81 .await
82 }
83
84 pub(super) async fn execute_top_level(
85 &mut self,
86 entry: TopLevelEntry,
87 ) -> Result<VmValue, VmError> {
88 self.ensure_execution_available()?;
89 let registry = self.pool_registry.clone();
90 let owner = crate::observability::execution_scope::mint_execution_scope();
91 let ambient = crate::orchestration::AmbientExecutionScope::capture_for_top_level_execution(
92 owner,
93 self.llm_mock_context.clone(),
94 );
95 let execution = crate::stdlib::pool::with_pool_registry_scope(registry, async {
96 self.execute_entry_scoped(entry).await
97 });
98 crate::orchestration::scope_ambient(ambient, execution).await
99 }
100
101 async fn execute_entry_scoped(&mut self, entry: TopLevelEntry) -> Result<VmValue, VmError> {
102 let _execution_activity = self
103 .wait_for_graph
104 .register_task(self.runtime_context.task_id.clone());
105 let _span = ScopeSpan::new(crate::tracing::SpanKind::Pipeline, "main".into());
106 match entry.run(self).await {
107 Ok(value) => self.run_pipeline_finish_lifecycle(value).await,
108 Err(error) => {
109 crate::orchestration::clear_pipeline_on_finish();
110 Err(error)
111 }
112 }
113 }
114}