arrpc 0.2.0

A simple RPC library for modular-monolith development
Documentation
use std::marker::PhantomData;

use anyhow::Context;
use arrpc::core::{ClientContract, MakeClient, Result, Service, ServiceContract, UniversalClient};
use async_trait::async_trait;
use serde::{de::DeserializeOwned, Serialize};
use serde_json::Value;

pub struct Request {
    input: Value,
}

impl arrpc::core::Request for Request {
    type Response = Response;
    fn proc<P: DeserializeOwned>(&self) -> Result<P> {
        serde_json::from_value(self.input.to_owned()).context("deserializing proc")
    }
    fn respond<V: Serialize>(self, value: V) -> Result<Response> {
        Ok(Response(
            serde_json::to_value(value).context("serializing response")?,
        ))
    }
}

pub struct Response(Value);

#[derive(Default)]
pub struct LocalContract<S>(PhantomData<S>);

#[async_trait]
impl<S> ServiceContract for LocalContract<S>
where
    S: Service + Send + Sync,
{
    type R = Request;
    async fn eval(&self, _: &Self::R) -> Result<()> {
        Ok(())
    }
}

#[async_trait]
impl<S> MakeClient for LocalContract<S>
where
    S: Service + Send + Sync,
{
    type Args = LocalService<S>;

    type Client = LocalContractClient<S>;

    fn make_client<A>(args: A) -> UniversalClient<Self::Client>
    where
        Self::Args: From<A>,
    {
        let local_svc: LocalService<S> = args.into();
        UniversalClient(LocalContractClient(local_svc.0))
    }
}

pub struct LocalContractClient<S>(S);
#[async_trait]
impl<S> ClientContract for LocalContractClient<S>
where
    S: Service + Send + Sync,
{
    async fn send<R, V>(&self, req: R) -> Result<V>
    where
        R: Serialize + Send + Sync,
        V: DeserializeOwned + Send + Sync,
    {
        let request = Request {
            input: serde_json::to_value(req).context("serializing request to Value")?,
        };
        let response = self.0.accept(request).await?;

        serde_json::from_value(response.0).context("deserializing from value")
    }
}

pub struct LocalService<S>(S);

impl<S> From<S> for LocalService<S> {
    fn from(value: S) -> Self {
        LocalService(value)
    }
}