use crate::{
args::{ArgValues, FromArgs},
asyncio::GatherFuture,
bytecode::{CallResult, VM},
defer_drop_mut,
exception_private::{ExcType, RunResult},
heap::{Heap, HeapData, HeapId},
intern::StaticStrings,
modules::ModuleFunctions,
resource::{ResourceError, ResourceTracker},
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<'_, impl ResourceTracker>) -> Result<HeapId, ResourceError> {
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(module))
}
pub(super) fn call(
vm: &mut VM<'_, impl ResourceTracker>,
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<impl ResourceTracker>, args: ArgValues) -> RunResult<CallResult> {
let coroutine = args.get_one_arg("asyncio.run", heap)?;
Ok(CallResult::AwaitValue(coroutine))
}
pub(crate) fn gather(vm: &mut VM<'_, impl ResourceTracker>, args: ArgValues) -> RunResult<Value> {
let GatherArgs { awaitables } = GatherArgs::from_args(args, vm)?;
defer_drop_mut!(awaitables, vm);
let mut items: Vec<HeapId> = Vec::new();
#[cfg_attr(not(feature = "memory-model-checks"), expect(unused_mut))]
for mut arg in awaitables.drain(..) {
let id = match &arg {
Value::Ref(id)
if matches!(
vm.heap.get(*id),
HeapData::Coroutine(_) | HeapData::ExternalFuture(_) | HeapData::GatherFuture(_)
) =>
{
Some(*id)
}
_ => None,
};
if let Some(id) = id {
items.push(id);
#[cfg(feature = "memory-model-checks")]
arg.dec_ref_forget();
} else {
arg.drop_with_heap(vm.heap);
for id in items {
vm.heap.dec_ref(id);
}
return Err(ExcType::type_error(
"An asyncio.Future, a coroutine or an awaitable is required",
));
}
}
let gather_future = GatherFuture::new(items);
let id = vm.heap.allocate(HeapData::GatherFuture(gather_future))?;
Ok(Value::Ref(id))
}
#[derive(FromArgs)]
#[from_args(name = "gather", kwargs_not_supported_yet)]
struct GatherArgs {
#[from_args(varargs)]
awaitables: Vec<Value>,
}