//! Direct binding — server-side only; calls Rust functions directly, zero network. //! //! Used when the component and the service implementation run in the same //! process. Eliminates all serialization/deserialization overhead. //! //! The handler registry maps `"ServiceName::method_name"` to a function pointer. //! The proxy calls the function directly. use super::{Binding, BindingKind, ServiceRequest, ServiceResponse}; use crate::{ServiceError, ServiceResult}; use std::collections::HashMap; use std::sync::{Arc, RwLock}; /// A direct handler function — takes params, returns a JSON body string. pub type DirectHandler = Arc) -> ServiceResult + Send + Sync>; /// Direct binding — calls registered Rust functions without any network hop. pub struct DirectBinding { /// Registry: `"ServiceName::method_name"` → handler fn handlers: Arc>>, } impl DirectBinding { pub fn new() -> Self { Self { handlers: Arc::new(RwLock::new(HashMap::new())), } } /// Register a handler for a service method. /// /// ``` /// # use el_services::binding::direct::DirectBinding; /// let binding = DirectBinding::new(); /// binding.register("UserService", "get_user", |params| { /// let id = params.get("id").map(|s| s.as_str()).unwrap_or("unknown"); /// Ok(format!("{{\"id\":\"{}\",\"name\":\"Alice\"}}", id)) /// }); /// ``` pub fn register( &self, service: &str, method: &str, handler: impl Fn(HashMap) -> ServiceResult + Send + Sync + 'static, ) { let key = format!("{}::{}", service, method); self.handlers .write() .expect("lock poisoned") .insert(key, Arc::new(handler)); } /// Check if a handler is registered. pub fn has_handler(&self, service: &str, method: &str) -> bool { let key = format!("{}::{}", service, method); self.handlers .read() .expect("lock poisoned") .contains_key(&key) } } impl Default for DirectBinding { fn default() -> Self { Self::new() } } impl Binding for DirectBinding { fn kind(&self) -> BindingKind { BindingKind::Direct } fn call(&self, request: ServiceRequest) -> ServiceResult { let key = format!("{}::{}", request.service, request.method); let handlers = self.handlers.read().expect("lock poisoned"); let handler = handlers.get(&key).ok_or_else(|| ServiceError::MethodNotFound { service: request.service.clone(), method: request.method.clone(), })?; let body = handler(request.params)?; Ok(ServiceResponse::ok(body)) } }