onion_vm/lambda/scheduler/
scheduler.rs

1use 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                        //self.result = *result;
63                        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        // {type: "Scheduler", frames: frame_json_array}
147        Ok(serde_json::json!({
148            "type": "Scheduler",
149            "frames": stack_json_array
150        }))
151    }
152}