Motore

Motore 是一个使用了 AFIT 和 RPITIT 特性的中间件抽象层。

基于 Motore,我们编写了一些模块化并且可复用的,用来编写 client 和 server 的组件。

Motore 深受Tower 启发。

简介

Motore 使用 AFIT 和 RPITIT 来减轻编写异步代码的精神负担,尤其是为了避免 Box 的开销而导致的负担,以减少使用者的焦虑。

Motore 最核心的抽象是 Service trait:

pub trait Service<Cx, Request> {
    /// Responses given by the service.
    type Response;
    /// Errors produced by the service.
    type Error;

    /// Process the request and return the response asynchronously.
    async fn call<'s, 'cx>(&'s mut self, cx: &'cx mut Cx, req: Request) -> Result<Self::Response, Self::Error>;
}

快速上手

使用 AFIT,我们可以以非常简洁易读的方式编写异步代码:

pub struct Timeout<S> {
    inner: S,
    duration: Duration,
}
impl<Cx, Req, S> Service<Cx, Req> for Timeout<S>
where
    Req: 'static + Send,
    S: Service<Cx, Req> + 'static + Send,
    Cx: 'static + Send,
    S::Error: Send + Sync + Into<BoxError>,
{
    type Response = S::Response;
    type Error = BoxError;

    async fn call<'s, 'cx>(&'s mut self, cx: &'cx mut Cx, req: Req) -> Result<Self::Response, Self::Error> {
        let sleep = tokio::time::sleep(self.duration);
        tokio::select! {
            r = self.inner.call(cx, req) => {
                r.map_err(Into::into)
            },
            _ = sleep => Err(std::io::Error::new(std::io::ErrorKind::TimedOut, "service time out").into()),
        }
    }
}

我们还提供了#[motore::service]宏以使编写 Service 更加像编写原生异步 Rust:

use motore::service;
pub struct S<I> {
    inner: I,
}
#[service]
impl<Cx, Req, I> Service<Cx, Req> for S<I>
where
   Req: Send + 'static,
   I: Service<Cx, Req> + Send + 'static,
   Cx: Send + 'static,
{
    async fn call(&mut self, cx: &mut Cx, req: Req) -> Result<I::Response, I::Error> {
        self.inner.call(cx, req).await
    }
}