Skip to main content

folk_api/
executor.rs

1//! The `Executor` trait — how plugins send work to PHP workers.
2//!
3//! `folk-core` provides the concrete implementation, backed by the worker pool.
4
5use std::any::Any;
6use std::sync::Arc;
7
8use anyhow::Result;
9use async_trait::async_trait;
10use bytes::Bytes;
11
12/// Sends a serialized payload to a PHP worker and returns the response.
13///
14/// Plugins call this; they never see the worker pool directly.
15#[async_trait]
16pub trait Executor: Send + Sync + 'static {
17    /// Send `payload` to a worker and return the response bytes.
18    /// Uses the RPC method name "dispatch" by default.
19    async fn execute(&self, payload: Bytes) -> Result<Bytes> {
20        self.execute_method("dispatch", payload).await
21    }
22
23    /// Send `payload` to a worker using a specific RPC method name.
24    async fn execute_method(&self, method: &str, payload: Bytes) -> Result<Bytes>;
25
26    /// Direct dispatch — optimized for embed runtime.
27    ///
28    /// Passes typed request data directly (no serialization). Returns
29    /// `Err` by default — callers should fall back to `execute_method`.
30    ///
31    /// Only `EmbedRuntime` implements this; pipe/fork runtimes use the default.
32    async fn execute_direct(
33        &self,
34        _method: &str,
35        _request: &(dyn Any + Send + Sync),
36    ) -> Result<Box<dyn Any + Send>> {
37        Err(anyhow::anyhow!(
38            "execute_direct not supported by this runtime"
39        ))
40    }
41}
42
43/// Blanket impl: an `Arc<dyn Executor>` is also an `Executor`.
44#[async_trait]
45impl<T: Executor + ?Sized> Executor for Arc<T> {
46    async fn execute_method(&self, method: &str, payload: Bytes) -> Result<Bytes> {
47        (**self).execute_method(method, payload).await
48    }
49
50    async fn execute_direct(
51        &self,
52        method: &str,
53        request: &(dyn Any + Send + Sync),
54    ) -> Result<Box<dyn Any + Send>> {
55        (**self).execute_direct(method, request).await
56    }
57}