folk-api 0.1.2

Plugin contract for the Folk PHP application server
Documentation
//! The `Executor` trait — how plugins send work to PHP workers.
//!
//! `folk-core` provides the concrete implementation, backed by the worker pool.

use std::any::Any;
use std::sync::Arc;

use anyhow::Result;
use async_trait::async_trait;
use bytes::Bytes;

/// Sends a serialized payload to a PHP worker and returns the response.
///
/// Plugins call this; they never see the worker pool directly.
#[async_trait]
pub trait Executor: Send + Sync + 'static {
    /// Send `payload` to a worker and return the response bytes.
    /// Uses the RPC method name "dispatch" by default.
    async fn execute(&self, payload: Bytes) -> Result<Bytes> {
        self.execute_method("dispatch", payload).await
    }

    /// Send `payload` to a worker using a specific RPC method name.
    async fn execute_method(&self, method: &str, payload: Bytes) -> Result<Bytes>;

    /// Direct dispatch — optimized for embed runtime.
    ///
    /// Passes typed request data directly (no serialization). Returns
    /// `Err` by default — callers should fall back to `execute_method`.
    ///
    /// Only `EmbedRuntime` implements this; pipe/fork runtimes use the default.
    async fn execute_direct(
        &self,
        _method: &str,
        _request: &(dyn Any + Send + Sync),
    ) -> Result<Box<dyn Any + Send>> {
        Err(anyhow::anyhow!(
            "execute_direct not supported by this runtime"
        ))
    }
}

/// Blanket impl: an `Arc<dyn Executor>` is also an `Executor`.
#[async_trait]
impl<T: Executor + ?Sized> Executor for Arc<T> {
    async fn execute_method(&self, method: &str, payload: Bytes) -> Result<Bytes> {
        (**self).execute_method(method, payload).await
    }

    async fn execute_direct(
        &self,
        method: &str,
        request: &(dyn Any + Send + Sync),
    ) -> Result<Box<dyn Any + Send>> {
        (**self).execute_direct(method, request).await
    }
}