#![deny(clippy::pedantic)]
#![allow(clippy::borrow_deref_ref)] #![allow(clippy::missing_panics_doc)] #![allow(clippy::used_underscore_binding)] #![warn(missing_docs)]
use once_cell::sync::OnceCell as OnceLock;
use pyo3::exceptions::PyRuntimeError;
use pyo3::types::{PyDict, PyTuple};
use pyo3::{IntoPy, PyAny, PyObject, PyResult, Python, ToPyObject};
pub mod any;
mod asyncio;
pub mod tokio;
pub mod traits;
mod trio;
pub use crate::asyncio::Asyncio;
use crate::traits::PyLoop;
pub use crate::trio::Trio;
static NONE: OnceLock<PyObject> = OnceLock::new();
static SYS_MODULES: OnceLock<PyObject> = OnceLock::new();
pub(crate) fn import_none(py: Python) -> &PyAny {
NONE.get_or_init(|| py.None()).as_ref(py)
}
fn import_sys_modules(py: Python) -> PyResult<&PyAny> {
SYS_MODULES
.get_or_try_init(|| Ok(py.import("sys")?.getattr("modules")?.to_object(py)))
.map(|value| value.as_ref(py))
}
#[pyo3::pyclass]
pub(crate) struct ContextWrap {
callback: PyObject,
context: Option<PyObject>,
}
impl ContextWrap {
fn py(context: Option<&PyAny>, callback: &PyAny) -> PyObject {
let py = callback.py();
Self {
callback: callback.to_object(py),
context: context.map(|value| value.to_object(py)),
}
.into_py(py)
}
}
#[pyo3::pymethods]
impl ContextWrap {
#[args(callback, args, kwargs = "None")]
fn __call__(&self, py: Python, mut args: Vec<PyObject>, kwargs: Option<&PyDict>) -> PyResult<PyObject> {
if let Some(context) = self.context.as_ref() {
args.insert(0, self.callback.clone_ref(py));
context.call_method(py, "run", PyTuple::new(py, args), kwargs)
} else {
self.callback.call(py, PyTuple::new(py, args), kwargs)
}
}
}
pub fn get_running_loop(py: Python) -> PyResult<Box<dyn PyLoop>> {
let modules = import_sys_modules(py)?;
if modules.contains("asyncio")? {
if let Some(loop_) = Asyncio::get_running_loop(py)? {
return Ok(Box::new(loop_));
}
};
if modules.contains("trio")? {
if let Some(loop_) = Trio::get_running_loop(py)? {
return Ok(Box::new(loop_));
}
};
Err(PyRuntimeError::new_err("No running event loop"))
}