externcrate std; use std::alloc::{self, Layout}; use std::any::Any; use std::boxed::Box; use std::collections::{hash_map, HashMap}; use std::fmt::{self, Debug, Display}; use std::future::Future; use std::pin::Pin; use std::ptr; use std::string::String; use std::sync::Arc; use std::task::{Context, Poll, Wake, Waker}; use std::vec::Vec;
use futures::channel::oneshot; use futures::future::FutureExt; use futures::stream::{FuturesUnordered, StreamExt}; use once_cell::sync::Lazy;
type BoxFuture = Pin<Box<dyn Future<Output = ()> + 'static>>;
/// Represents a task created by either a call to an async-lifted export or a /// future run using `block_on` or `poll_future`. struct FutureState { /// Number of in-progress async-lowered import calls and/or stream/future reads/writes.
todo: usize, /// Remaining work to do (if any) before this task can be considered "done". /// /// Note that we won't tell the host the task is done until this is drained /// and `todo` is zero.
tasks: Option<FuturesUnordered<BoxFuture>>,
}
/// Represents the state of a stream or future. #[doc(hidden)] pubenum Handle {
LocalOpen,
LocalReady(Box<dyn Any>, Waker),
LocalWaiting(oneshot::Sender<Box<dyn Any>>),
LocalClosed,
Read,
Write,
}
/// The current task being polled (or null if none). staticmut CURRENT: *mut FutureState = ptr::null_mut();
/// Map of any in-progress calls to async-lowered imports, keyed by the /// identifiers issued by the host. staticmut CALLS: Lazy<HashMap<i32, oneshot::Sender<u32>>> = Lazy::new(HashMap::new);
/// Any newly-deferred work queued by calls to the `spawn` function while /// polling the current task. staticmut SPAWNED: Vec<BoxFuture> = Vec::new();
/// The states of all currently-open streams and futures. staticmut HANDLES: Lazy<HashMap<u32, Handle>> = Lazy::new(HashMap::new);
/// Poll the specified task until it either completes or can't make immediate /// progress. unsafefn poll(state: *mut FutureState) -> Poll<()> { loop { iflet Some(futures) = (*state).tasks.as_mut() {
CURRENT = state; let poll = futures.poll_next_unpin(&mut Context::from_waker(&dummy_waker()));
CURRENT = ptr::null_mut();
/// Poll the future generated by a call to an async-lifted export once, calling /// the specified closure (presumably backed by a call to `task.return`) when it /// generates a value. /// /// This will return a non-null pointer representing the task if it hasn't /// completed immediately; otherwise it returns null. #[doc(hidden)] pubfn first_poll<T: 'static>(
future: impl Future<Output = T> + 'static,
fun: impl FnOnce(&T) + 'static,
) -> *mut u8 { let state = Box::into_raw(Box::new(FutureState {
todo: 0,
tasks: Some(
[Box::pin(future.map(|v| fun(&v))) as BoxFuture]
.into_iter()
.collect(),
),
})); matchunsafe { poll(state) } {
Poll::Ready(()) => ptr::null_mut(),
Poll::Pending => state as _,
}
}
/// stream/future read/write results defined by the Component Model ABI. mod results { pubconst BLOCKED: u32 = 0xffff_ffff; pubconst CLOSED: u32 = 0x8000_0000; pubconst CANCELED: u32 = 0;
}
/// Await the completion of a future read or write. #[doc(hidden)] pubasyncunsafefn await_future_result(
import: unsafeextern"C"fn(u32, *mut u8) -> u32,
future: u32,
address: *mut u8,
) -> bool { let result = import(future, address); match result {
results::BLOCKED => {
assert!(!CURRENT.is_null());
(*CURRENT).todo += 1; let (tx, rx) = oneshot::channel();
CALLS.insert(future as _, tx); let v = rx.await.unwrap();
v == 1
}
results::CLOSED | results::CANCELED => false, 1 => true,
_ => unreachable!(),
}
}
/// Await the completion of a stream read or write. #[doc(hidden)] pubasyncunsafefn await_stream_result(
import: unsafeextern"C"fn(u32, *mut u8, u32) -> u32,
stream: u32,
address: *mut u8,
count: u32,
) -> Option<usize> { let result = import(stream, address, count); match result {
results::BLOCKED => {
assert!(!CURRENT.is_null());
(*CURRENT).todo += 1; let (tx, rx) = oneshot::channel();
CALLS.insert(stream as _, tx); let v = rx.await.unwrap(); iflet results::CLOSED | results::CANCELED = v {
None
} else {
Some(usize::try_from(v).unwrap())
}
}
results::CLOSED | results::CANCELED => None,
v => Some(usize::try_from(v).unwrap()),
}
}
/// Defer the specified future to be run after the current async-lifted export /// task has returned a value. /// /// The task will remain in a running state until all spawned futures have /// completed. pubfn spawn(future: impl Future<Output = ()> + 'static) { unsafe { SPAWNED.push(Box::pin(future)) }
}
/// Run the specified future to completion, returning the result. /// /// This uses `task.wait` to poll for progress on any in-progress calls to /// async-lowered imports as necessary. // TODO: refactor so `'static` bounds aren't necessary pubfn block_on<T: 'static>(future: impl Future<Output = T> + 'static) -> T { let (tx, mut rx) = oneshot::channel(); let state = &mut FutureState {
todo: 0,
tasks: Some(
[Box::pin(future.map(move |v| drop(tx.send(v)))) as BoxFuture]
.into_iter()
.collect(),
),
}; loop { matchunsafe { poll(state) } {
Poll::Ready(()) => break rx.try_recv().unwrap().unwrap(),
Poll::Pending => task_wait(state),
}
}
}
/// Call the `task.yield` canonical built-in function. /// /// This yields control to the host temporarily, allowing other tasks to make /// progress. It's a good idea to call this inside a busy loop which does not /// otherwise ever yield control the the host. pubfn task_yield() { #[cfg(not(target_arch = "wasm32"))]
{
unreachable!();
}
/// Call the `task.backpressure` canonical built-in function. /// /// When `enabled` is `true`, this tells the host to defer any new calls to this /// component instance until further notice (i.e. until `task.backpressure` is /// called again with `enabled` set to `false`). pubfn task_backpressure(enabled: bool) { #[cfg(not(target_arch = "wasm32"))]
{
_ = enabled;
unreachable!();
}
unsafe { let handle = context_new(debug_message.as_ptr(), debug_message.len()); // SAFETY: Handles (including error context handles are guaranteed to // fit inside u32 by the Component Model ABI
ErrorContext::from_handle(u32::try_from(handle).unwrap())
}
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.