onion_vm/lambda/scheduler/
scheduler.rs1use std::sync::Arc;
2
3use arc_gc::gc::GC;
4
5use crate::{
6 lambda::runnable::{Runnable, RuntimeError, StepResult},
7 types::{
8 object::{OnionObject, OnionObjectCell},
9 pair::OnionPair,
10 },
11};
12
13pub struct Scheduler {
14 pub(crate) runnable_stack: Vec<Box<dyn Runnable>>,
15}
16
17impl Scheduler {
18 pub fn new(runnable_stack: Vec<Box<dyn Runnable>>) -> Self {
19 Scheduler { runnable_stack }
20 }
21}
22
23impl Runnable for Scheduler {
24 fn step(&mut self, gc: &mut GC<OnionObjectCell>) -> StepResult {
25 if let Some(runnable) = self.runnable_stack.last_mut() {
26 match runnable.step(gc) {
27 StepResult::Continue => StepResult::Continue,
28 v @ StepResult::SpawnRunnable(_) => return v,
29 StepResult::NewRunnable(new_runnable) => {
30 self.runnable_stack.push(new_runnable);
31 StepResult::Continue
32 }
33 StepResult::ReplaceRunnable(new_runnable) => {
34 self.runnable_stack.last_mut().map(|r| *r = new_runnable);
35 StepResult::Continue
36 }
37 StepResult::Return(ref result) => {
38 self.runnable_stack.pop();
39 if let Some(top_runnable) = self.runnable_stack.last_mut() {
40 match top_runnable.receive(&StepResult::Return(result.clone()), gc) {
41 Ok(_) => {}
42 Err(RuntimeError::CustomValue(ref e)) => {
43 return StepResult::Return(
44 OnionPair::new_static(
45 &OnionObject::Boolean(false).stabilize(),
46 &e,
47 )
48 .into(),
49 );
50 }
51 Err(e) => {
52 return StepResult::Return(
53 OnionPair::new_static(
54 &OnionObject::Boolean(false).stabilize(),
55 &OnionObject::String(Arc::from(e.to_string())).stabilize(),
56 )
57 .into(),
58 );
59 }
60 };
61 StepResult::Continue
62 } else {
63 StepResult::Return(
65 OnionPair::new_static(
66 &OnionObject::Boolean(true).stabilize(),
67 result.as_ref(),
68 )
69 .into(),
70 )
71 }
72 }
73 StepResult::Error(ref error) => {
74 if let RuntimeError::Pending = error {
75 return StepResult::Error(RuntimeError::Pending);
77 }
78 return StepResult::Return(
79 OnionPair::new_static(
80 &OnionObject::Boolean(false).stabilize(),
81 &match error {
82 RuntimeError::CustomValue(v) => v.as_ref().clone(),
83 _ => OnionObject::Undefined(Some(error.to_string().into()))
84 .stabilize(),
85 },
86 )
87 .into(),
88 );
89 }
90 }
91 } else {
92 StepResult::Error(RuntimeError::DetailedError(
93 "No runnable in stack".into(),
94 ))
95 }
96 }
97 fn receive(
98 &mut self,
99 step_result: &StepResult,
100 gc: &mut GC<OnionObjectCell>,
101 ) -> Result<(), RuntimeError> {
102 if let Some(runnable) = self.runnable_stack.last_mut() {
103 runnable.receive(&step_result, gc)
104 } else {
105 Err(RuntimeError::DetailedError(
106 "No runnable in stack".into(),
107 ))
108 }
109 }
110
111 fn format_context(&self) -> String {
112 if self.runnable_stack.is_empty() {
113 return "Scheduler: No active runnables.".to_string();
114 }
115
116 let contexts: Vec<String> = self
119 .runnable_stack
120 .iter()
121 .rev() .enumerate() .map(|(index, runnable)| {
124 let header = format!("--- Frame #{} ---", index);
125 let inner_context = runnable.format_context();
126 format!("{}\n{}", header, inner_context)
127 })
128 .collect();
129
130 contexts.join("\n\n") }
133}