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
#[macro_export]
macro_rules! impl_wrapping_obj_from_num {
    ($host_fn: ident, $hot: ty, $obj: ty, $num: ty) => {
        fn $host_fn(&self, _vmcaller: &mut VmCaller<Host>, u: $num) -> Result<$obj, HostError> {
            self.add_host_object(<$hot>::from(u))
        }
    };
}

#[macro_export]
macro_rules! impl_wrapping_obj_to_num {
    ($host_fn: ident, $data: ty, $obj: ty, $num: ty) => {
        fn $host_fn(&self, _vmcaller: &mut VmCaller<Host>, obj: $obj) -> Result<$num, HostError> {
            self.visit_obj(obj, |t: &$data| Ok(t.metered_clone(self)?.into()))
        }
    };
}

#[macro_export]
macro_rules! impl_bignum_host_fns {
    ($host_fn: ident, $method: ident, $num: ty, $valty: ty, $cost: ident) => {
        fn $host_fn(
            &self,
            _vmcaller: &mut VmCaller<Self::VmUserState>,
            lhs_val: $valty,
            rhs_val: $valty,
        ) -> Result<$valty, Self::Error> {
            use soroban_env_common::TryIntoVal;
            self.charge_budget(ContractCostType::$cost, None)?;
            let lhs: $num = lhs_val.to_val().try_into_val(self)?;
            let rhs: $num = rhs_val.to_val().try_into_val(self)?;
            let res: $num = lhs.$method(rhs).ok_or_else(|| {
                self.err(
                    ScErrorType::Object,
                    ScErrorCode::ArithDomain,
                    "overflow has occured",
                    &[lhs_val.to_val(), rhs_val.to_val()],
                )
            })?;
            Ok(res.try_into_val(self)?)
        }
    };
}

#[macro_export]
macro_rules! impl_bignum_host_fns_rhs_u32 {
    ($host_fn: ident, $method: ident, $num: ty, $valty: ty, $cost: ident) => {
        fn $host_fn(
            &self,
            _vmcaller: &mut VmCaller<Self::VmUserState>,
            lhs_val: $valty,
            rhs_val: U32Val,
        ) -> Result<$valty, Self::Error> {
            use soroban_env_common::TryIntoVal;
            self.charge_budget(ContractCostType::$cost, None)?;
            let lhs: $num = lhs_val.to_val().try_into_val(self)?;
            let res = lhs.$method(rhs_val.into()).ok_or_else(|| {
                self.err(
                    ScErrorType::Object,
                    ScErrorCode::ArithDomain,
                    "overflow has occured",
                    &[lhs_val.to_val(), rhs_val.to_val()],
                )
            })?;
            Ok(res.try_into_val(self)?)
        }
    };
}