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 StepResult::NewRunnable(new_runnable) => {
29 self.runnable_stack.push(new_runnable);
30 StepResult::Continue
31 }
32 StepResult::ReplaceRunnable(new_runnable) => {
33 self.runnable_stack.last_mut().map(|r| *r = new_runnable);
34 StepResult::Continue
35 }
36 StepResult::Return(ref result) => {
37 self.runnable_stack.pop();
38 if let Some(top_runnable) = self.runnable_stack.last_mut() {
39 match top_runnable.receive(&StepResult::Return(result.clone()), gc) {
40 Ok(_) => {}
41 Err(RuntimeError::CustomValue(ref e)) => {
42 return StepResult::Return(
43 OnionPair::new_static(
44 &OnionObject::Boolean(false).stabilize(),
45 &e,
46 )
47 .into(),
48 )
49 }
50 Err(e) => {
51 return StepResult::Return(
52 OnionPair::new_static(
53 &OnionObject::Boolean(false).stabilize(),
54 &OnionObject::String(Arc::new(e.to_string())).stabilize(),
55 )
56 .into(),
57 )
58 }
59 };
60 StepResult::Continue
61 } else {
62 StepResult::Return(
64 OnionPair::new_static(
65 &OnionObject::Boolean(true).stabilize(),
66 result.as_ref(),
67 )
68 .into(),
69 )
70 }
71 }
72 StepResult::SetSelfObject(ref self_object) => {
73 if let Some(top_runnable) = self.runnable_stack.last_mut() {
74 match top_runnable
75 .receive(&StepResult::SetSelfObject(self_object.clone()), gc)
76 {
77 Ok(_) => {}
78 Err(RuntimeError::CustomValue(ref e)) => {
79 return StepResult::Return(
80 OnionPair::new_static(
81 &OnionObject::Boolean(false).stabilize(),
82 &e,
83 )
84 .into(),
85 )
86 }
87 Err(e) => {
88 return StepResult::Return(
89 OnionPair::new_static(
90 &OnionObject::Boolean(false).stabilize(),
91 &OnionObject::String(Arc::new(e.to_string())).stabilize(),
92 )
93 .into(),
94 )
95 }
96 }
97 }
98 StepResult::Continue
99 }
100 StepResult::Error(ref error) => {
101 return StepResult::Return(
102 OnionPair::new_static(
103 &OnionObject::Boolean(false).stabilize(),
104 &match error {
105 RuntimeError::CustomValue(ref v) => v.as_ref().clone(),
106 _ => OnionObject::Undefined(Some(error.to_string().into()))
107 .stabilize(),
108 },
109 )
110 .into(),
111 )
112 }
113 }
114 } else {
115 StepResult::Error(RuntimeError::DetailedError(
116 "No runnable in stack".to_string().into(),
117 ))
118 }
119 }
120 fn receive(
121 &mut self,
122 step_result: &StepResult,
123 gc: &mut GC<OnionObjectCell>,
124 ) -> Result<(), RuntimeError> {
125 if let Some(runnable) = self.runnable_stack.last_mut() {
126 runnable.receive(&step_result, gc)
127 } else {
128 Err(RuntimeError::DetailedError(
129 "No runnable in stack".to_string().into(),
130 ))
131 }
132 }
133
134 fn copy(&self) -> Box<dyn Runnable> {
135 Box::new(Scheduler {
136 runnable_stack: self.runnable_stack.iter().map(|r| r.copy()).collect(),
137 })
138 }
139
140 fn format_context(&self) -> Result<serde_json::Value, RuntimeError> {
141 let mut stack_json_array = serde_json::Value::Array(vec![]);
142 for runnable in &self.runnable_stack {
143 let frame_json = runnable.format_context()?;
144 stack_json_array.as_array_mut().unwrap().push(frame_json);
145 }
146 Ok(serde_json::json!({
148 "type": "Scheduler",
149 "frames": stack_json_array
150 }))
151 }
152}