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::new(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::SetSelfObject(ref self_object) => {
74 if let Some(top_runnable) = self.runnable_stack.last_mut() {
75 match top_runnable
76 .receive(&StepResult::SetSelfObject(self_object.clone()), gc)
77 {
78 Ok(_) => {}
79 Err(RuntimeError::CustomValue(ref e)) => {
80 return StepResult::Return(
81 OnionPair::new_static(
82 &OnionObject::Boolean(false).stabilize(),
83 &e,
84 )
85 .into(),
86 )
87 }
88 Err(e) => {
89 return StepResult::Return(
90 OnionPair::new_static(
91 &OnionObject::Boolean(false).stabilize(),
92 &OnionObject::String(Arc::new(e.to_string())).stabilize(),
93 )
94 .into(),
95 )
96 }
97 }
98 }
99 StepResult::Continue
100 }
101 StepResult::Error(ref error) => {
102 if let RuntimeError::Pending = error {
103 return StepResult::Error(RuntimeError::Pending);
105 }
106 return StepResult::Return(
107 OnionPair::new_static(
108 &OnionObject::Boolean(false).stabilize(),
109 &match error {
110 RuntimeError::CustomValue(ref v) => v.as_ref().clone(),
111 _ => OnionObject::Undefined(Some(error.to_string().into()))
112 .stabilize(),
113 },
114 )
115 .into(),
116 );
117 }
118 }
119 } else {
120 StepResult::Error(RuntimeError::DetailedError(
121 "No runnable in stack".to_string().into(),
122 ))
123 }
124 }
125 fn receive(
126 &mut self,
127 step_result: &StepResult,
128 gc: &mut GC<OnionObjectCell>,
129 ) -> Result<(), RuntimeError> {
130 if let Some(runnable) = self.runnable_stack.last_mut() {
131 runnable.receive(&step_result, gc)
132 } else {
133 Err(RuntimeError::DetailedError(
134 "No runnable in stack".to_string().into(),
135 ))
136 }
137 }
138
139 fn copy(&self) -> Box<dyn Runnable> {
140 Box::new(Scheduler {
141 runnable_stack: self.runnable_stack.iter().map(|r| r.copy()).collect(),
142 })
143 }
144
145 fn format_context(&self) -> Result<serde_json::Value, RuntimeError> {
146 let mut stack_json_array = serde_json::Value::Array(vec![]);
147 for runnable in &self.runnable_stack {
148 let frame_json = runnable.format_context()?;
149 stack_json_array.as_array_mut().unwrap().push(frame_json);
150 }
151 Ok(serde_json::json!({
153 "type": "Scheduler",
154 "frames": stack_json_array
155 }))
156 }
157}