use super::task::APIServerReq;
use crate::{Codec, error::RpcIntErr};
use rustc_hash::FxHashMap;
use std::sync::Arc;
pub trait ServiceStatic<C: Codec>: Send + Sync + 'static + Sized {
const SERVICE_NAME: &'static str;
fn serve(&self, req: APIServerReq<C>) -> impl Future<Output = ()> + Send + Sized;
}
impl<S: ServiceStatic<C>, C: Codec> ServiceStatic<C> for Arc<S> {
const SERVICE_NAME: &'static str = S::SERVICE_NAME;
#[inline(always)]
fn serve(&self, req: APIServerReq<C>) -> impl Future<Output = ()> + Send + Sized {
self.as_ref().serve(req)
}
}
#[async_trait::async_trait]
pub trait ServiceDyn<C: Codec>: Send + Sync + 'static {
fn get_service_name(&self) -> &'static str;
async fn serve_dyn(&self, req: APIServerReq<C>);
}
#[async_trait::async_trait]
impl<S: ServiceStatic<C>, C: Codec> ServiceDyn<C> for S {
#[inline(always)]
fn get_service_name(&self) -> &'static str {
<Self as ServiceStatic<C>>::SERVICE_NAME
}
#[inline(always)]
async fn serve_dyn(&self, req: APIServerReq<C>) {
self.serve(req).await
}
}
pub struct ServiceMuxDyn<C: Codec> {
map: FxHashMap<&'static str, Arc<dyn ServiceDyn<C>>>,
}
impl<C: Codec> ServiceMuxDyn<C> {
#[inline]
pub fn new() -> Self {
Self { map: Default::default() }
}
#[inline]
pub fn add(&mut self, service: Arc<dyn ServiceDyn<C>>) {
self.map.insert(service.get_service_name(), service);
}
}
impl<C: Codec> ServiceStatic<C> for ServiceMuxDyn<C> {
const SERVICE_NAME: &'static str = "";
#[inline(always)]
fn serve(&self, req: APIServerReq<C>) -> impl Future<Output = ()> + Send + Sized {
async move {
if let Some(service) = self.map.get(req.service.as_str()) {
service.serve_dyn(req).await
} else {
req.set_rpc_error(RpcIntErr::Service);
}
}
}
}