wasmtime/runtime/store/
context.rs

1use crate::store::{Store, StoreInner};
2
3/// A temporary handle to a [`&Store<T>`][`Store`].
4///
5/// This type is suitable for [`AsContext`] trait bounds on methods if desired.
6/// For more information, see [`Store`].
7// NB the repr(transparent) here is for the C API and it's important that the
8// representation of this `struct` is a pointer for now. If the representation
9// changes then the C API will need to be updated
10#[repr(transparent)]
11pub struct StoreContext<'a, T>(pub(crate) &'a StoreInner<T>);
12
13/// A temporary handle to a [`&mut Store<T>`][`Store`].
14///
15/// This type is suitable for [`AsContextMut`] or [`AsContext`] trait bounds on
16/// methods if desired.  For more information, see [`Store`].
17// NB the repr(transparent) here is for the same reason as above.
18#[repr(transparent)]
19pub struct StoreContextMut<'a, T>(pub(crate) &'a mut StoreInner<T>);
20
21impl<'a, T> StoreContextMut<'a, T> {
22    /// One of the unsafe lynchpins of Wasmtime.
23    ///
24    /// This method is called from one location, `Caller::with`, and is where we
25    /// load the raw unsafe trait object pointer from a `*mut VMContext` and
26    /// then cast it back to a `StoreContextMut`. This is naturally unsafe due
27    /// to the raw pointer usage, but it's also unsafe because `T` here needs to
28    /// line up with the `T` used to define the trait object itself.
29    ///
30    /// This should generally be achieved with various trait bounds throughout
31    /// Wasmtime that might give access to the `Caller<'_, T>` type.
32    /// Unfortunately there's not a ton of debug asserts we can add here, so we
33    /// rely on testing to largely help show that this is correctly used.
34    pub(crate) unsafe fn from_raw(
35        store: *mut dyn crate::runtime::vm::Store,
36    ) -> StoreContextMut<'a, T> {
37        StoreContextMut(&mut *(store as *mut StoreInner<T>))
38    }
39}
40
41/// A trait used to get shared access to a [`Store`] in Wasmtime.
42///
43/// This trait is used as a bound on the first argument of many methods within
44/// Wasmtime. This trait is implemented for types like [`Store`],
45/// [`Caller`](crate::Caller), and [`StoreContext`] itself. Implementors of this
46/// trait provide access to a [`StoreContext`] via some means, allowing the
47/// method in question to get access to the store's internal information.
48///
49/// Note that this is only used in contexts where the store's information is
50/// read, but not written. For example methods that return type information will
51/// use this trait as a bound. More commonly, though, mutation is required and
52/// [`AsContextMut`] is needed.
53pub trait AsContext {
54    /// The host information associated with the [`Store`], aka the `T` in
55    /// [`Store<T>`].
56    type Data;
57
58    /// Returns the store context that this type provides access to.
59    fn as_context(&self) -> StoreContext<'_, Self::Data>;
60}
61
62/// A trait used to get exclusive mutable access to a [`Store`] in Wasmtime.
63///
64/// This trait is used as a bound on the first argument of many methods within
65/// Wasmtime. This trait is implemented for types like [`Store`],
66/// [`Caller`](crate::Caller), and [`StoreContextMut`] itself. Implementors of
67/// this trait provide access to a [`StoreContextMut`] via some means, allowing
68/// the method in question to get access to the store's internal information.
69///
70/// This is notably used for methods that may require some mutation of the
71/// [`Store`] itself. For example calling a wasm function can mutate linear
72/// memory or globals. Creation of a [`Func`](crate::Func) will update internal
73/// data structures. This ends up being quite a common bound in Wasmtime, but
74/// typically you can simply pass `&mut store` or `&mut caller` to satisfy it.
75///
76/// # Calling multiple methods that take `&mut impl AsContextMut`
77///
78/// As of Rust 1.53.0, [generic methods that take a generic `&mut T` do not get
79/// "automatic reborrowing"][reborrowing] and therefore you cannot call multiple
80/// generic methods with the same `&mut T` without manually inserting
81/// reborrows. This affects the many `wasmtime` API methods that take `&mut impl
82/// AsContextMut`.
83///
84/// For example, this fails to compile because the context is moved into the
85/// first call:
86///
87/// ```compile_fail
88/// use wasmtime::{AsContextMut, Instance};
89///
90/// fn foo(cx: &mut impl AsContextMut, instance: Instance) {
91///     // `cx` is not reborrowed, but moved into this call.
92///     let my_export = instance.get_export(cx, "my_export");
93///
94///     // Therefore, this use of `cx` is a use-after-move and prohibited by the
95///     // borrow checker.
96///     let other_export = instance.get_export(cx, "other_export");
97/// #   drop((my_export, other_export));
98/// }
99/// ```
100///
101/// To fix this, manually insert reborrows like `&mut *cx` that would otherwise
102/// normally be inserted automatically by the Rust compiler for non-generic
103/// methods:
104///
105/// ```
106/// use wasmtime::{AsContextMut, Instance};
107///
108/// fn foo(cx: &mut impl AsContextMut, instance: Instance) {
109///     let my_export = instance.get_export(&mut *cx, "my_export");
110///
111///     // This works now, since `cx` was reborrowed above, rather than moved!
112///     let other_export = instance.get_export(&mut *cx, "other_export");
113/// #   drop((my_export, other_export));
114/// }
115/// ```
116///
117/// [reborrowing]: https://github.com/rust-lang/rust/issues/85161
118pub trait AsContextMut: AsContext {
119    /// Returns the store context that this type provides access to.
120    fn as_context_mut(&mut self) -> StoreContextMut<'_, Self::Data>;
121}
122
123impl<T> AsContext for Store<T> {
124    type Data = T;
125
126    #[inline]
127    fn as_context(&self) -> StoreContext<'_, T> {
128        StoreContext(&self.inner)
129    }
130}
131
132impl<T> AsContextMut for Store<T> {
133    #[inline]
134    fn as_context_mut(&mut self) -> StoreContextMut<'_, T> {
135        StoreContextMut(&mut self.inner)
136    }
137}
138
139impl<T> AsContext for StoreContext<'_, T> {
140    type Data = T;
141
142    #[inline]
143    fn as_context(&self) -> StoreContext<'_, T> {
144        StoreContext(&*self.0)
145    }
146}
147
148impl<T> AsContext for StoreContextMut<'_, T> {
149    type Data = T;
150
151    #[inline]
152    fn as_context(&self) -> StoreContext<'_, T> {
153        StoreContext(&*self.0)
154    }
155}
156
157impl<T> AsContextMut for StoreContextMut<'_, T> {
158    #[inline]
159    fn as_context_mut(&mut self) -> StoreContextMut<'_, T> {
160        StoreContextMut(&mut *self.0)
161    }
162}
163
164impl<'a, T> From<StoreContextMut<'a, T>> for StoreContext<'a, T> {
165    #[inline]
166    fn from(store: StoreContextMut<'a, T>) -> StoreContext<'a, T> {
167        StoreContext(store.0)
168    }
169}
170
171// Implementations for internal consumers, but these aren't public types so
172// they're not publicly accessible for crate consumers.
173impl<T> AsContext for &'_ StoreInner<T> {
174    type Data = T;
175
176    #[inline]
177    fn as_context(&self) -> StoreContext<'_, T> {
178        StoreContext(self)
179    }
180}
181
182impl<T> AsContext for &'_ mut StoreInner<T> {
183    type Data = T;
184
185    #[inline]
186    fn as_context(&self) -> StoreContext<'_, T> {
187        StoreContext(self)
188    }
189}
190
191impl<T> AsContextMut for &'_ mut StoreInner<T> {
192    #[inline]
193    fn as_context_mut(&mut self) -> StoreContextMut<'_, T> {
194        StoreContextMut(&mut **self)
195    }
196}
197
198// forward AsContext for &T
199impl<T: AsContext> AsContext for &'_ T {
200    type Data = T::Data;
201
202    #[inline]
203    fn as_context(&self) -> StoreContext<'_, T::Data> {
204        T::as_context(*self)
205    }
206}
207
208// forward AsContext for &mut T
209impl<T: AsContext> AsContext for &'_ mut T {
210    type Data = T::Data;
211
212    #[inline]
213    fn as_context(&self) -> StoreContext<'_, T::Data> {
214        T::as_context(*self)
215    }
216}
217
218// forward AsContextMut for &mut T
219impl<T: AsContextMut> AsContextMut for &'_ mut T {
220    #[inline]
221    fn as_context_mut(&mut self) -> StoreContextMut<'_, T::Data> {
222        T::as_context_mut(*self)
223    }
224}
225
226//
227impl<'a, T: AsContext> From<&'a T> for StoreContext<'a, T::Data> {
228    fn from(t: &'a T) -> StoreContext<'a, T::Data> {
229        t.as_context()
230    }
231}
232
233impl<'a, T: AsContext> From<&'a mut T> for StoreContext<'a, T::Data> {
234    fn from(t: &'a mut T) -> StoreContext<'a, T::Data> {
235        T::as_context(t)
236    }
237}
238
239impl<'a, T: AsContextMut> From<&'a mut T> for StoreContextMut<'a, T::Data> {
240    fn from(t: &'a mut T) -> StoreContextMut<'a, T::Data> {
241        t.as_context_mut()
242    }
243}