pub struct Accessor<T: 'static, D = HasSelf<T>>{ /* private fields */ }runtime and component-model and component-model-async only.Expand description
Provides scoped mutable access to store data in the context of a concurrent host task future.
This allows multiple host task futures to execute concurrently and access
the store between (but not across) await points.
§Rationale
This structure is sort of like &mut T plus a projection from &mut T to
D::Data<'_>. The problem this is solving, however, is that it does not
literally store these values. The basic problem is that when a concurrent
host future is being polled it has access to &mut T (and the whole
Store) but when it’s not being polled it does not have access to these
values. This reflects how the store is only ever polling one future at a
time so the store is effectively being passed between futures.
Rust’s Future trait, however, has no means of passing a Store
temporarily between futures. The Context type does
not have the ability to attach arbitrary information to it at this time.
This type, Accessor, is used to bridge this expressivity gap.
The Accessor type here represents the ability to acquire, temporarily in
a synchronous manner, the current store. The Accessor::with function
yields an Access which can be used to access StoreContextMut, &mut T, or D::Data<'_>. Note though that Accessor::with intentionally does
not take an async closure as its argument, instead it’s a synchronous
closure which must complete during on run of Future::poll. This reflects
how the store is temporarily made available while a host future is being
polled.
§Implementation
This type does not actually store &mut T nor StoreContextMut<T>, and
this type additionally doesn’t even have a lifetime parameter. This is
instead a representation of proof of the ability to acquire these while a
future is being polled. Wasmtime will, when it polls a host future,
configure ambient state such that the Accessor that a future closes over
will work and be able to access the store.
This has a number of implications for users such as:
- It’s intentional that
Accessorcannot be cloned, it needs to stay within the lifetime of a single future. - A future is expected to, however, close over an
Accessorand keep it alive probably for the duration of the entire future. - Different host futures will be given different
Accessors, and that’s intentional. - The
Accessortype isSendandSyncirrespective ofTwhich alleviates some otherwise required bounds to be written down.
§Using Accessor in Drop
The methods on Accessor are only expected to work in the context of
Future::poll and are not guaranteed to work in Drop. This is because a
host future can be dropped at any time throughout the system and Wasmtime
store context is not necessarily available at that time. It’s recommended to
not use Accessor methods in anything connected to a Drop implementation
as they will panic and have unintended results. If you run into this though
feel free to file an issue on the Wasmtime repository.
Implementations§
Source§impl<T, D> Accessor<T, D>
impl<T, D> Accessor<T, D>
Sourcepub fn with<R>(&self, fun: impl FnOnce(Access<'_, T, D>) -> R) -> R
pub fn with<R>(&self, fun: impl FnOnce(Access<'_, T, D>) -> R) -> R
Run the specified closure, passing it mutable access to the store.
This function is one of the main building blocks of the Accessor
type. This yields synchronous, blocking, access to store via an
Access. The Access implements AsContextMut in addition to
providing the ability to access D via Access::get. Note that the
fun here is given only temporary access to the store and T/D
meaning that the return value R here is not allowed to capture borrows
into the two. If access is needed to data within T or D outside of
this closure then it must be cloned out, for example.
§Panics
This function will panic if it is call recursively with any other
accessor already in scope. For example if with is called within fun,
then this function will panic. It is up to the embedder to ensure that
this does not happen.
Sourcepub fn getter(&self) -> fn(&mut T) -> D::Data<'_>
pub fn getter(&self) -> fn(&mut T) -> D::Data<'_>
Returns the getter this accessor is using to project from T into
D::Data.
Sourcepub fn with_getter<D2: HasData>(
&self,
get_data: fn(&mut T) -> D2::Data<'_>,
) -> Accessor<T, D2>
pub fn with_getter<D2: HasData>( &self, get_data: fn(&mut T) -> D2::Data<'_>, ) -> Accessor<T, D2>
Changes this accessor to access D2 instead of the current type
parameter D.
This changes the underlying data access from T to D2::Data<'_>.
§Panics
When using this API the returned value is disconnected from &self and
the lifetime binding the self argument. An Accessor only works
within the context of the closure or async closure that it was
originally given to, however. This means that due to the fact that the
returned value has no lifetime connection it’s possible to use the
accessor outside of &self, the original accessor, and panic.
The returned value should only be used within the scope of the original
Accessor that self refers to.
Sourcepub fn spawn(&self, task: impl AccessorTask<T, D, Result<()>>) -> JoinHandle ⓘwhere
T: 'static,
pub fn spawn(&self, task: impl AccessorTask<T, D, Result<()>>) -> JoinHandle ⓘwhere
T: 'static,
Spawn a background task which will receive an &Accessor<T, D> and
run concurrently with any other tasks in progress for the current
store.
This is particularly useful for host functions which return a stream
or future such that the code to write to the write end of that
stream or future must run after the function returns.
The returned JoinHandle may be used to cancel the task.
§Panics
Panics if called within a closure provided to the Accessor::with
function. This can only be called outside an active invocation of
Accessor::with.
Trait Implementations§
Source§impl<T, D: HasData + ?Sized> AsAccessor for Accessor<T, D>
impl<T, D: HasData + ?Sized> AsAccessor for Accessor<T, D>
Source§type AccessorData = D
type AccessorData = D
D in Accessor<T, D>, or the projection out of
Self::Data.Source§fn as_accessor(&self) -> &Accessor<T, D>
fn as_accessor(&self) -> &Accessor<T, D>
Auto Trait Implementations§
impl<T, D> Freeze for Accessor<T, D>where
D: ?Sized,
impl<T, D> RefUnwindSafe for Accessor<T, D>where
D: ?Sized,
impl<T, D> Send for Accessor<T, D>where
D: ?Sized,
impl<T, D> Sync for Accessor<T, D>where
D: ?Sized,
impl<T, D> Unpin for Accessor<T, D>where
D: ?Sized,
impl<T, D> UnwindSafe for Accessor<T, D>where
D: ?Sized,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more