Trait forth3::dictionary::AsyncBuiltins
source · pub trait AsyncBuiltins<'forth, T: 'static> {
type Future: Future<Output = Result<(), Error>>;
const BUILTINS: &'static [AsyncBuiltinEntry<T>];
// Required method
fn dispatch_async(
&self,
id: &'static FaStr,
forth: &'forth mut Forth<T>,
) -> Self::Future;
}
async
only.Expand description
A set of asynchronous builtin words, and a method to dispatch builtin names
to Future
s.
This trait is used along with the AsyncForth
type to
allow some builtin words to be implemented by async fn
s (or Future
s),
rather than synchronous functions. See here for an overview of
how asynchronous Forth VMs work.
§Implementing Async Builtins
Synchronous builtins are provided to the Forth VM as a static slice of
BuiltinEntry
s. These entries allow the VM to lookup builtin words by
name, and also contain a function pointer to the host function that
implements that builtin. Asynchronous builtins work somewhat differently: a
slice of AsyncBuiltinEntry
s is still used in order to define the names
of the asynchronous builtin words, but because asynchronous functions return
a Future
whose type must be known, an AsyncBuiltinEntry
does not
contain a function pointer to a host function. Instead, once the name of an
async builtin is looked up, it is passed to the
AsyncBuiltins::dispatch_async
method, which returns the Future
corresponding to that builtin function.
This indirection allows the AsyncBuiltins
trait to erase the various
Future
types which are returned by the async builtin functions, allowing
the AsyncForth
VM to have only a single additional generic parameter for
the AsyncBuiltins
implementation itself. Without the indirection of
dispatch_async
, the AsyncForth
VM would need to be generic over
every possible Future
type that may be returned by an async builtin
word, which would be impractical.1
In order to erase multiple Future
types, one of several approaches may
be used:
- The
Future
returned bydispatch_async
can be anenum
of each builtin word’sFuture
type. This requires all builtin words to be implemented as namedFuture
types, rather thanasync fn
s, but does not require heap allocation or unstable Rust features. - The
Future
type can be aPin<Box<dyn Future<Output = Result<(), Error>> + 'forth>
. This requires heap allocation, but can erase the type of any number of async builtin futures, which may beasync fn
s or namedFuture
types. - If using nightly Rust, the
#![feature(impl_trait_in_assoc_type)]
unstable feature can be enabled, allowing theAsyncBuiltins::Future
associated type to beimpl Future<Output = Result(), Error> + 'forth
. This does not require heap allocation, and allows thedispatch_async
method to return anasync
blockFuture
whichmatch
es on the builtin’s name and calls any number ofasync fn
s or namedFuture
types. This is the preferred approach when nightly features may be used.
Since the AsyncBuiltins
trait is generic over the lifetime for which the
Forth
vm is borrowed mutably, the AsyncBuiltins::Future
associated
type may also be generic over that lifetime. This allows the returned
Future
to borrow the Forth
VM so that its stacks can be mutated
while the builtin Future
executes (e.g. the result of the asynchronous
operation can be pushed to the VM’s data
stack, et cetera).
If the
AsyncForth
type was generic over every possible async builtin future, it would have a large number of generic type parameters which would all need to be filled in by the user. Additionally, because Rust does not allow a type to have a variadic number of generic parameters, there would have to be an arbitrary limit on the maximum number of async builtin words. ↩
Required Associated Types§
Required Associated Constants§
sourceconst BUILTINS: &'static [AsyncBuiltinEntry<T>]
const BUILTINS: &'static [AsyncBuiltinEntry<T>]
A static slice of AsyncBuiltinEntry
s describing the builtins
provided by this implementation of AsyncBuiltin
s.
AsyncBuiltinEntry
s may be created using the
async_builtin!
macro.
Required Methods§
sourcefn dispatch_async(
&self,
id: &'static FaStr,
forth: &'forth mut Forth<T>,
) -> Self::Future
fn dispatch_async( &self, id: &'static FaStr, forth: &'forth mut Forth<T>, ) -> Self::Future
Dispatch a builtin name (id
) to an asynchronous builtin Future
.
The returned Future
may borrow the Forth
VM
provided as an argument to this function, allowing it to mutate the VM’s
stacks as it executes.
This method should return a Future
for each builtin function
definition in Self::BUILTINS
. Typically, this is implemented by
match
ing the provided id
, and returning the appropriate Future
for each builtin name. See the AsyncBuiltin
trait’s
documentation for details on implementing this method.
The id
parameter is 'static
, as we will only resolve function names
from the provided Self::BUILTINS
, which must be 'static
.