You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
As ut-utp/tui#12 explains, supporting a WebSerial backed Transport implementation is tricky because the WebSerial APIs are all async.
This requires us to make the Transport trait's methods async which is turn requires the Control trait to be async (because of the Control impl on Controller), etc.
We don't want to do this unconditionally (i.e. on all platforms) because currently the solution for async traits makes heavy use of trait objects and allocates which is problematic for embedded devices.
Ideally we'd have something that looks like keyword generics to support this use case but that's a ways off. Luckily, there's good prior art in the space of using proc macros to emulate this kind of functionality: maybe-async.
Since we're looking to tie the "async-ness" of some of our traits and functions to the target we're compiling for (instead of to a cargo feature) we can leverage maybe-async's must_be_async and must_be_sync attributes in conjunction with some carefully crafted #[cfg_attr(..., ...)] attributes.
We can even go a step further and spin this off into our own proc_macro attributes along with a wrapper crate so that we don't have to explicitly depend on maybe-async everywhere:
/* macro-impl crate *//// Effectively equivalent to:/// ```ignore/// #[cfg_attr(target_family = "wasm", maybe_async::must_be_async)]/// #[cfg_attr(not(target_family = "wasm"), maybe_async::must_be_sync)]/// .../// ```////// Note that `async-trait` must be a dep when targeting `wasm`; you probably/// want to add something like this to your `Cargo.toml`:/// ```toml/// [target.'cfg(target_family = "wasm")'.dependencies]/// async-trait = "0.1"/// ```#[proc_macro_attribute]pubfnasync_on_wasm(args:TokenStream,input:TokenStream) -> TokenStream{letmut out:TokenStream = quote!{
#[cfg_attr(target_family = "wasm",::lc3_macros::macro_support::must_be_async)]
#[cfg_attr(not(target_family = "wasm"),::lc3_macros::macro_support::must_be_sync)]}.into();
out.extend([input]);
out
}
what
As ut-utp/tui#12 explains, supporting a
WebSerial
backedTransport
implementation is tricky because theWebSerial
APIs are allasync
.This requires us to make the
Transport
trait's methods async which is turn requires theControl
trait to be async (because of theControl
impl onController
), etc.We don't want to do this unconditionally (i.e. on all platforms) because currently the solution for async traits makes heavy use of trait objects and allocates which is problematic for embedded devices.
Ideally we'd have something that looks like keyword generics to support this use case but that's a ways off. Luckily, there's good prior art in the space of using proc macros to emulate this kind of functionality:
maybe-async
.Since we're looking to tie the "async-ness" of some of our traits and functions to the target we're compiling for (instead of to a cargo feature) we can leverage
maybe-async
'smust_be_async
andmust_be_sync
attributes in conjunction with some carefully crafted#[cfg_attr(..., ...)]
attributes.We can even go a step further and spin this off into our own proc_macro attributes along with a wrapper crate so that we don't have to explicitly depend on
maybe-async
everywhere:steps
where
branch:
feat/async-everywhere
open questions
The text was updated successfully, but these errors were encountered: