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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
use super::super::{AsContext, AsContextMut, StoreContext, StoreContextMut};
use crate::{store::FuelError, Engine, Extern, Instance};

/// Represents the caller’s context when creating a host function via [`Func::wrap`].
///
/// [`Func::wrap`]: struct.Func.html#method.wrap
pub struct Caller<'a, T> {
    ctx: StoreContextMut<'a, T>,
    /// The module instance associated to the call.
    /// This is `Some` if the host function was called from a Wasm function
    /// since all Wasm function are associated to a module instance.
    /// This usually is `None` if the host function was called from the host side.
    instance: Option<Instance>,
}

impl<'a, T> Caller<'a, T> {
    /// Creates a new [`Caller`] from the given store context and [`Instance`] handle.
    pub fn new<C>(ctx: &'a mut C, instance: Option<&Instance>) -> Self
    where
        C: AsContextMut<UserState = T>,
    {
        Self {
            ctx: ctx.as_context_mut(),
            instance: instance.copied(),
        }
    }

    /// Queries the caller for an exported definition identifier by `name`.
    ///
    /// Returns `None` if there is no associated [`Instance`] of the caller
    /// or if the caller does not provide an export under the name `name`.
    pub fn get_export(&self, name: &str) -> Option<Extern> {
        self.instance
            .and_then(|instance| instance.get_export(self, name))
    }

    /// Returns a shared reference to the user provided host data.
    pub fn data(&self) -> &T {
        self.ctx.store.data()
    }

    /// Returns an exclusive reference to the user provided host data.
    pub fn data_mut(&mut self) -> &mut T {
        self.ctx.store.data_mut()
    }

    /// Returns a shared reference to the used [`Engine`].
    pub fn engine(&self) -> &Engine {
        self.ctx.store.engine()
    }

    /// Adds `delta` quantity of fuel to the remaining fuel.
    ///
    /// # Panics
    ///
    /// If this overflows the remaining fuel counter.
    ///
    /// # Errors
    ///
    /// If fuel metering is disabled.
    pub fn add_fuel(&mut self, delta: u64) -> Result<(), FuelError> {
        self.ctx.store.add_fuel(delta)
    }

    /// Returns the amount of fuel consumed by executions of the [`Store`](crate::Store) so far.
    ///
    /// Returns `None` if fuel metering is disabled.
    pub fn fuel_consumed(&self) -> Option<u64> {
        self.ctx.store.fuel_consumed()
    }

    /// Returns the amount of total [`Fuel`] supplied to the [`Store`](crate::Store).
    ///
    /// Returns `None` if fuel metering is disabled.
    pub fn fuel_total(&self) -> Option<u64> {
        self.ctx.store.fuel_total()
    }

    /// Synthetically consumes an amount of fuel for the [`Store`](crate::Store).
    ///
    /// Returns the remaining amount of fuel after this operation.
    ///
    /// # Panics
    ///
    /// If this overflows the consumed fuel counter.
    ///
    /// # Errors
    ///
    /// - If fuel metering is disabled.
    /// - If more fuel is consumed than available.
    pub fn consume_fuel(&mut self, delta: u64) -> Result<u64, FuelError> {
        self.ctx.store.consume_fuel(delta)
    }

    /// Resets the total and consumed amounts of fuel to 0 for the [`Store`](crate::Store).
    ///
    /// # Errors
    ///
    /// - If fuel metering is disabled.
    pub fn reset_fuel(&mut self) -> Result<(), FuelError> {
        self.ctx.store.reset_fuel()
    }
}

impl<T> AsContext for Caller<'_, T> {
    type UserState = T;

    #[inline]
    fn as_context(&self) -> StoreContext<'_, Self::UserState> {
        self.ctx.as_context()
    }
}

impl<T> AsContextMut for Caller<'_, T> {
    #[inline]
    fn as_context_mut(&mut self) -> StoreContextMut<'_, Self::UserState> {
        self.ctx.as_context_mut()
    }
}

impl<'a, T: AsContextMut> From<&'a mut T> for Caller<'a, T::UserState> {
    #[inline]
    fn from(ctx: &'a mut T) -> Self {
        Self {
            ctx: ctx.as_context_mut(),
            instance: None,
        }
    }
}