use crate::{
args::{ArgValues, FromArgs},
asyncio::GatherFuture,
bytecode::{CallResult, VM},
defer_drop_mut,
exception_private::{ExcType, ExcTypeExt, RunResult},
heap::{Heap, HeapData, HeapId},
intern::StaticStrings,
modules::ModuleFunctions,
types::Module,
value::Value,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum::Display, serde::Serialize, serde::Deserialize)]
#[strum(serialize_all = "lowercase")]
pub(crate) enum AsyncioFunctions {
Gather,
Run,
}
pub fn create_module(vm: &mut VM<'_>) -> HeapId {
let mut module = Module::new(StaticStrings::Asyncio);
module.set_attr(
StaticStrings::Gather,
Value::ModuleFunction(ModuleFunctions::Asyncio(AsyncioFunctions::Gather)),
vm,
);
module.set_attr(
StaticStrings::Run,
Value::ModuleFunction(ModuleFunctions::Asyncio(AsyncioFunctions::Run)),
vm,
);
vm.heap.allocate(HeapData::Module(Box::new(module)))
}
pub(super) fn call(vm: &mut VM<'_>, functions: AsyncioFunctions, args: ArgValues) -> RunResult<CallResult> {
match functions {
AsyncioFunctions::Gather => gather(vm, args).map(CallResult::Value),
AsyncioFunctions::Run => run(vm.heap, args),
}
}
fn run(heap: &mut Heap, args: ArgValues) -> RunResult<CallResult> {
let coroutine = args.get_one_arg("asyncio.run", heap)?;
Ok(CallResult::AwaitValue(coroutine))
}
pub(crate) fn gather(vm: &mut VM<'_>, args: ArgValues) -> RunResult<Value> {
let GatherArgs { awaitables } = GatherArgs::from_args(args, vm)?;
defer_drop_mut!(awaitables, vm);
for arg in awaitables.iter() {
if !matches!(
arg,
Value::Ref(id)
if matches!(
vm.heap.get(*id),
HeapData::Coroutine(_) | HeapData::ExternalFuture(_) | HeapData::GatherFuture(_)
)
) {
return Err(ExcType::type_error(
"An asyncio.Future, a coroutine or an awaitable is required",
));
}
}
let items = awaitables
.drain(..)
.map(|arg| arg.into_ref_id().expect("validated gather awaitable is heap-backed"))
.collect();
let gather_future = GatherFuture::new(items);
let id = vm.heap.allocate(HeapData::GatherFuture(Box::new(gather_future)));
Ok(Value::Ref(id))
}
#[derive(FromArgs)]
#[from_args(name = "gather", kwargs_not_supported_yet)]
struct GatherArgs {
#[from_args(varargs)]
awaitables: Vec<Value>,
}