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