alef 0.23.35

Opinionated polyglot binding generator for Rust libraries
Documentation
impl {{ core_import }}::{{ trait_name }} for {{ bridge_name }} {
    fn {{ dispatch_name }}(
        &self{{ extra_param }},
        {{ wire_name }}: {{ req_path }},
    ) -> Pin<Box<dyn Future<Output = {{ output_type }}> + Send + '_>> {
        // Acquire Python GIL in a thread-safe context before entering the async block.
        // Py<PyAny> holds a GIL-independent reference that can be used outside the GIL.
        let callable = pyo3::Python::attach(|py| self.callable.clone_ref(py));
        let is_async = self.is_async;

        Box::pin(async move {
            let outcome: {{ wire_output }} = async move {
                // Serialize the request to a Python-friendly dict via serde_json
                let req_json = serde_json::to_string(&{{ wire_name }})
                    .map_err(|e| Box::new(e) as {{ box_err }})?;

                let raw_result = if is_async {
                    // Async callable: hand off to pyo3_async_runtimes so it drives
                    // the Python event loop without blocking the Tokio executor.
                    let future = pyo3::Python::attach(|py| -> PyResult<_> {
                        let req_obj = py.import("json")?.call_method1("loads", (&req_json,))?;
                        let coro = callable.call1(py, (req_obj,))?;
                        pyo3_async_runtimes::tokio::into_future(coro.into_bound(py))
                    })
                    .map_err(|e| Box::new(e) as {{ box_err }})?;
                    let py_result = future.await
                        .map_err(|e| Box::new(e) as {{ box_err }})?;
                    pyo3::Python::attach(|py| {
                        let json_mod = py.import("json")?;
                        let json_str: String = json_mod
                            .call_method1("dumps", (py_result.bind(py),))?
                            .extract()?;
                        Ok::<String, PyErr>(json_str)
                    })
                    .map_err(|e| Box::new(e) as {{ box_err }})?
                } else {
                    // Sync callable: run in a blocking thread so we never hold the GIL
                    // on the async executor.
                    tokio::task::spawn_blocking(move || {
                        pyo3::Python::attach(|py| {
                            let req_obj = py.import("json")?.call_method1("loads", (&req_json,))?;
                            let result = callable.call1(py, (req_obj,))?;
                            let json_mod = py.import("json")?;
                            let json_str: String = json_mod
                                .call_method1("dumps", (result.bind(py),))?
                                .extract()?;
                            Ok::<String, PyErr>(json_str)
                        })
                    })
                    .await
                    .map_err(|e| Box::new(e) as {{ box_err }})?
                    .map_err(|e| Box::new(e) as {{ box_err }})?
                };

                // Deserialize the JSON result back into the wire response DTO.
                let response: {{ resp_path }} = serde_json::from_str(&raw_result)
                    .map_err(|e| Box::new(e) as {{ box_err }})?;
                Ok(response)
            }
            .await;

            {{ tail }}
        })
    }
}