1use std::ops::Deref;
2
3use anyhow::Context;
4use async_trait::async_trait;
5use serde::{de::DeserializeOwned, Serialize};
6
7pub use anyhow::Result;
8
9#[async_trait]
10pub trait Service {
11 async fn accept<R>(&self, req: R) -> Result<R::Response>
12 where
13 R: Request + Send + Sync;
14}
15
16#[async_trait]
17pub trait ServiceContract: MakeClient {
18 type R: Request + Send + Sync;
19 async fn eval(&self, req: &Self::R) -> Result<()>;
20}
21
22#[async_trait]
23pub trait ClientContract {
24 async fn send<R, V>(&self, req: R) -> Result<V>
25 where
26 R: Serialize + Send + Sync,
27 V: DeserializeOwned + Send + Sync;
28}
29
30pub trait Request {
31 type Response;
32 fn proc<P: DeserializeOwned>(&self) -> Result<P>;
33 fn respond<V: Serialize>(self, value: V) -> Result<Self::Response>;
34}
35
36pub struct UniversalClient<T>(pub T);
37
38pub struct UniversalServer<Contract, Service> {
39 pub contract: Contract,
40 pub service: Service,
41}
42
43impl<C, S> UniversalServer<C, S>
44where
45 C: ServiceContract,
46 S: Deref,
47 S::Target: Service,
48{
49 pub async fn accept(&self, req: C::R) -> Result<<C::R as Request>::Response> {
50 self.contract
51 .eval(&req)
52 .await
53 .context("verifying contract")?;
54
55 self.service
56 .accept(req)
57 .await
58 .context("service called with proc")
59 }
60}
61
62pub trait MakeClient {
63 type Args;
64 type Client: ClientContract;
65
66 fn make_client<A>(args: A) -> UniversalClient<Self::Client>
67 where
68 Self::Args: From<A>;
69}