runestick/
protocol_caller.rs1use crate::{GuardedArgs, Hash, Protocol, Stack, UnitFn, Value, Vm, VmError, VmErrorKind};
2
3pub(crate) trait ProtocolCaller {
5 fn call_protocol_fn<A>(
7 self,
8 protocol: Protocol,
9 target: Value,
10 args: A,
11 ) -> Result<Value, VmError>
12 where
13 A: GuardedArgs;
14}
15
16pub(crate) struct EnvProtocolCaller;
20
21impl ProtocolCaller for EnvProtocolCaller {
22 fn call_protocol_fn<A>(
23 self,
24 protocol: Protocol,
25 target: Value,
26 args: A,
27 ) -> Result<Value, VmError>
28 where
29 A: GuardedArgs,
30 {
31 return crate::env::with(|context, unit| {
32 let count = args.count() + 1;
33 let hash = Hash::instance_function(target.type_hash()?, protocol.hash);
34
35 if let Some(UnitFn::Offset {
36 offset,
37 args: expected,
38 call,
39 }) = unit.lookup(hash)
40 {
41 check_args(count, expected)?;
42
43 let mut stack = Stack::with_capacity(count);
44 stack.push(target);
45
46 let _guard = unsafe { args.unsafe_into_stack(&mut stack)? };
48
49 let mut vm = Vm::new_with_stack(context.clone(), unit.clone(), stack);
50 vm.set_ip(offset);
51 return call.call_with_vm(vm);
52 }
53
54 let handler = match context.lookup(hash) {
55 Some(handler) => handler,
56 None => return Err(VmError::from(VmErrorKind::MissingFunction { hash })),
57 };
58
59 let mut stack = Stack::with_capacity(count);
60 stack.push(target);
61
62 let _guard = unsafe { args.unsafe_into_stack(&mut stack)? };
64
65 handler(&mut stack, count)?;
66 Ok(stack.pop()?)
67 });
68
69 fn check_args(args: usize, expected: usize) -> Result<(), VmError> {
71 if args != expected {
72 return Err(VmError::from(VmErrorKind::BadArgumentCount {
73 actual: args,
74 expected,
75 }));
76 }
77
78 Ok(())
79 }
80 }
81}
82
83impl ProtocolCaller for &mut Vm {
84 fn call_protocol_fn<A>(
85 self,
86 protocol: Protocol,
87 target: Value,
88 args: A,
89 ) -> Result<Value, VmError>
90 where
91 A: GuardedArgs,
92 {
93 if !self.call_instance_fn(target, protocol, args)? {
94 return Err(VmError::from(VmErrorKind::MissingFunction {
95 hash: protocol.hash,
96 }));
97 }
98
99 Ok(self.stack.pop()?)
100 }
101}