1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
use std::ops::Deref;

use anyhow::Context;
use async_trait::async_trait;
use serde::{de::DeserializeOwned, Serialize};

pub use anyhow::Result;

#[async_trait]
pub trait Service {
    async fn accept<R>(&self, req: R) -> Result<R::Response>
    where
        R: Request + Send + Sync;
}

#[async_trait]
pub trait ServiceContract: MakeClient {
    type R: Request + Send + Sync;
    async fn eval(&self, req: &Self::R) -> Result<()>;
}

#[async_trait]
pub trait ClientContract {
    async fn send<R, V>(&self, req: R) -> Result<V>
    where
        R: Serialize + Send + Sync,
        V: DeserializeOwned + Send + Sync;
}

pub trait Request {
    type Response;
    fn proc<P: DeserializeOwned>(&self) -> Result<P>;
    fn respond<V: Serialize>(self, value: V) -> Result<Self::Response>;
}

pub struct UniversalClient<T>(pub T);

pub struct UniversalServer<Contract, Service> {
    pub contract: Contract,
    pub service: Service,
}

impl<C, S> UniversalServer<C, S>
where
    C: ServiceContract,
    S: Deref,
    S::Target: Service,
{
    pub async fn accept(&self, req: C::R) -> Result<<C::R as Request>::Response> {
        self.contract
            .eval(&req)
            .await
            .context("verifying contract")?;

        self.service
            .accept(req)
            .await
            .context("service called with proc")
    }
}

pub trait MakeClient {
    type Args;
    type Client: ClientContract;

    fn make_client<A>(args: A) -> UniversalClient<Self::Client>
    where
        Self::Args: From<A>;
}