rune/runtime/
vm_call.rs
1use ::rust_alloc::sync::Arc;
2
3use crate::alloc::prelude::*;
4use crate::runtime::vm_execution::VmExecutionState;
5use crate::runtime::{
6 Call, Future, Generator, Output, RuntimeContext, Stack, Stream, Unit, Value, Vm, VmErrorKind,
7 VmExecution, VmResult,
8};
9
10#[derive(Debug)]
12#[must_use = "The construction of a vm call leaves the virtual machine stack in an intermediate state, VmCall::into_execution must be called to fix it"]
13pub(crate) struct VmCall {
14 call: Call,
16 context: Option<Arc<RuntimeContext>>,
18 unit: Option<Arc<Unit>>,
20 out: Output,
22}
23
24impl VmCall {
25 pub(crate) fn new(
26 call: Call,
27 context: Option<Arc<RuntimeContext>>,
28 unit: Option<Arc<Unit>>,
29 out: Output,
30 ) -> Self {
31 Self {
32 call,
33 context,
34 unit,
35 out,
36 }
37 }
38
39 #[tracing::instrument(skip_all)]
41 pub(crate) fn into_execution<T>(self, execution: &mut VmExecution<T>) -> VmResult<()>
42 where
43 T: AsRef<Vm> + AsMut<Vm>,
44 {
45 let out = self.out;
46
47 let value = match self.call {
48 Call::Async => {
49 let vm = vm_try!(self.build_vm(execution));
50 let mut execution = vm.into_execution();
51 vm_try!(Value::try_from(vm_try!(Future::new(async move {
52 execution.async_complete().await
53 }))))
54 }
55 Call::Immediate => {
56 vm_try!(execution.push_state(VmExecutionState {
57 context: self.context,
58 unit: self.unit,
59 }));
60
61 return VmResult::Ok(());
62 }
63 Call::Stream => {
64 let vm = vm_try!(self.build_vm(execution));
65 vm_try!(Value::try_from(Stream::new(vm)))
66 }
67 Call::Generator => {
68 let vm = vm_try!(self.build_vm(execution));
69 vm_try!(Value::try_from(Generator::new(vm)))
70 }
71 };
72
73 vm_try!(out.store(execution.vm_mut().stack_mut(), value));
74 VmResult::Ok(())
75 }
76
77 #[tracing::instrument(skip_all)]
78 fn build_vm<T>(self, execution: &mut VmExecution<T>) -> VmResult<Vm>
79 where
80 T: AsRef<Vm> + AsMut<Vm>,
81 {
82 let vm = execution.vm_mut();
83
84 let new_stack = vm_try!(vm.stack_mut().drain().try_collect::<Stack>());
85
86 let Some(ip) = vm.pop_call_frame_from_call() else {
87 return VmResult::err(VmErrorKind::MissingCallFrame);
88 };
89
90 let context = self.context.unwrap_or_else(|| vm.context().clone());
91 let unit = self.unit.unwrap_or_else(|| vm.unit().clone());
92
93 let mut vm = Vm::with_stack(context, unit, new_stack);
94 vm.set_ip(ip);
95 VmResult::Ok(vm)
96 }
97}