use std::collections::{BTreeMap, BTreeSet, VecDeque};
use wasmtime::component::types::{self, Type};
use wasmtime::component::ResourceType;
use wasmtime::Engine;
pub fn wasi_io_stream_resources(
engine: &Engine,
component: &types::Component,
) -> Vec<ResourceType> {
let mut imports = BTreeMap::new();
crate::collect_component_resource_imports(engine, component, &mut imports);
let mut out = Vec::new();
for (instance, resources) in imports {
let base = instance.split('@').next().unwrap_or(&instance);
if base != "wasi:io/streams" {
continue;
}
for (name, ty) in resources {
if (&*name == "input-stream" || &*name == "output-stream") && !out.contains(&ty) {
out.push(ty);
}
}
}
out
}
fn async_paths(ty: &Type, streams: &[ResourceType]) -> (BTreeSet<VecDeque<Option<usize>>>, bool) {
let mut paths = BTreeSet::new();
match ty {
Type::List(ty) => {
let (nested, fut) = async_paths(&ty.ty(), streams);
for mut path in nested {
path.push_front(None);
paths.insert(path);
}
if fut {
paths.insert(VecDeque::from([None]));
}
(paths, false)
}
Type::Option(ty) => async_paths(&ty.ty(), streams),
Type::Result(ty) => {
let mut is_fut = false;
if let Some(ty) = ty.ok() {
let (nested, fut) = async_paths(&ty, streams);
paths.extend(nested);
is_fut |= fut;
}
if let Some(ty) = ty.err() {
let (nested, fut) = async_paths(&ty, streams);
paths.extend(nested);
is_fut |= fut;
}
(paths, is_fut)
}
Type::Variant(ty) => {
let mut is_fut = false;
for case in ty.cases() {
if let Some(ty) = case.ty {
let (nested, fut) = async_paths(&ty, streams);
paths.extend(nested);
is_fut |= fut;
}
}
(paths, is_fut)
}
Type::Tuple(ty) => {
for (i, ty) in ty.types().enumerate() {
let (nested, fut) = async_paths(&ty, streams);
for mut path in nested {
path.push_front(Some(i));
paths.insert(path);
}
if fut {
paths.insert(VecDeque::from([Some(i)]));
}
}
(paths, false)
}
Type::Record(ty) => {
for (i, field) in ty.fields().enumerate() {
let (nested, fut) = async_paths(&field.ty, streams);
for mut path in nested {
path.push_front(Some(i));
paths.insert(path);
}
if fut {
paths.insert(VecDeque::from([Some(i)]));
}
}
(paths, false)
}
Type::Future(ty) => {
if let Some(ty) = ty.ty() {
(paths, _) = async_paths(&ty, streams);
}
(paths, true)
}
Type::Stream(ty) => {
if let Some(ty) = ty.ty() {
let (nested, fut) = async_paths(&ty, streams);
for mut path in nested {
path.push_front(None);
paths.insert(path);
}
if fut {
paths.insert(VecDeque::from([None]));
}
}
(paths, true)
}
Type::Own(ty) | Type::Borrow(ty) if streams.contains(ty) => {
(paths, true)
}
_ => (paths, false),
}
}
pub(crate) fn params_async_paths<'a>(
params: impl IntoIterator<Item = &'a Type>,
streams: &[ResourceType],
) -> Vec<Box<[Option<usize>]>> {
let mut out = BTreeSet::new();
for (i, ty) in params.into_iter().enumerate() {
let (nested, fut) = async_paths(ty, streams);
for mut path in nested {
path.push_front(Some(i));
out.insert(path);
}
if fut {
out.insert(VecDeque::from([Some(i)]));
}
}
out.into_iter()
.map(|path| path.into_iter().collect::<Box<[_]>>())
.collect()
}