Browse Source

add flowy-sys crate

appflowy 4 years ago
parent
commit
4d91ed147d

+ 2 - 1
.gitignore

@@ -9,4 +9,5 @@ Cargo.lock
 # These are backup files generated by rustfmt
 **/*.rs.bk
 
-/rust-lib
+/rust-lib/flowy-ast
+/rust-lib/flowy-derive

+ 3 - 0
.idea/appflowy_client.iml

@@ -3,6 +3,9 @@
   <component name="NewModuleRootManager">
     <content url="file://$MODULE_DIR$">
       <sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-ast/src" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-derive/src" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-derive/tests" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/rust-lib/flowy-sys/src" isTestSource="false" />
       <excludeFolder url="file://$MODULE_DIR$/app_flowy/packages/af_protobuf/.pub" />
       <excludeFolder url="file://$MODULE_DIR$/app_flowy/packages/af_protobuf/.dart_tool" />
       <excludeFolder url="file://$MODULE_DIR$/app_flowy/packages/af_protobuf/build" />

+ 1 - 0
README.md

@@ -12,6 +12,7 @@
 * [**Roadmap**](doc/roadmap.md)
 * [**Deep Dive AppFlowy**](doc/architecture.md)
 
+
 ## Contributing
 Read the [Contributing Doc](doc/contribute.md) before you want to contribute.
 

+ 26 - 2
doc/architecture.md

@@ -12,8 +12,32 @@
 ## ๐Ÿ“š Component Design
     
 ### ๐Ÿ“• Component 1
+
+
 ### ๐Ÿ“— Component 2
-### ๐Ÿ“˜ Component 3
-### ๐Ÿ“™ Component 3
 
 
+### ๐Ÿ“˜ Flutter Event Flow
+
+
+### ๐Ÿ“™ Rust Event Flow
+
+```
+                                                                          โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
+                                                                       โ”Œโ”€โ–ถโ”‚Service Aโ”‚
+                                                                       โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
+                           โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
+                        โ”Œโ”€โ–ถโ”‚Module A โ”‚โ”€โ–ถโ”‚ Services  โ”‚โ”€โ–ถโ”‚Deps Resolvedโ”‚โ”€โ”ผโ”€โ–ถโ”‚Service Bโ”‚
+                        โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
+                        โ”‚                                              โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
+โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                                 โ””โ”€โ–ถโ”‚Service Cโ”‚
+โ”‚ Event โ”‚โ”€โ”€โ–ถโ”‚Runtime โ”‚โ”€โ”€โ”ผโ”€โ–ถโ”‚Module B โ”‚                                    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
+โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
+                        โ”‚
+                        โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
+                        โ””โ”€โ–ถโ”‚Module C โ”‚
+                           โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
+```
+
+* sync will cause typing lag
+

+ 10 - 0
rust-lib/.gitignore

@@ -0,0 +1,10 @@
+# Generated by Cargo
+# will have compiled files and executables
+/target/
+
+# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
+# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
+Cargo.lock
+
+# These are backup files generated by rustfmt
+**/*.rs.bk

+ 7 - 0
rust-lib/Cargo.toml

@@ -0,0 +1,7 @@
+[workspace]
+members = [
+  "flowy-sys",
+]
+
+[profile.dev]
+split-debuginfo = "unpacked"

+ 15 - 0
rust-lib/flowy-sys/Cargo.toml

@@ -0,0 +1,15 @@
+[package]
+name = "flowy-sys"
+version = "0.1.0"
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+pin-project = "1.0.0"
+futures-core = { version = "0.3", default-features = false }
+paste = "1"
+futures-channel = "0.3.15"
+futures = "0.3.15"
+futures-util = "0.3.15"
+bytes = "0.5"

+ 150 - 0
rust-lib/flowy-sys/src/error.rs

@@ -0,0 +1,150 @@
+use crate::response::{FlowyResponse, StatusCode};
+use std::cell::RefCell;
+use std::fmt;
+
+pub struct Error {
+    inner: Box<dyn HandlerError>,
+}
+
+impl Error {
+    pub fn as_handler_error(&self) -> &dyn HandlerError {
+        self.inner.as_ref()
+    }
+}
+
+impl fmt::Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(&self.inner, f)
+    }
+}
+
+impl fmt::Debug for Error {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{:?}", &self.inner)
+    }
+}
+
+impl std::error::Error for Error {
+    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+        None
+    }
+
+    fn cause(&self) -> Option<&dyn std::error::Error> {
+        None
+    }
+}
+
+impl From<Error> for FlowyResponse {
+    fn from(err: Error) -> Self {
+        FlowyResponse::from_error(err)
+    }
+}
+
+impl From<FlowyResponse> for Error {
+    fn from(res: FlowyResponse) -> Error {
+        InternalError::from_response("", res).into()
+    }
+}
+
+/// `Error` for any error that implements `ResponseError`
+impl<T: HandlerError + 'static> From<T> for Error {
+    fn from(err: T) -> Error {
+        Error {
+            inner: Box::new(err),
+        }
+    }
+}
+
+pub trait HandlerError: fmt::Debug + fmt::Display {
+    fn status_code(&self) -> StatusCode;
+
+    fn as_response(&self) -> FlowyResponse {
+        let resp = FlowyResponse::new(self.status_code());
+        resp
+    }
+}
+
+pub struct InternalError<T> {
+    inner: T,
+    status: InternalErrorType,
+}
+
+enum InternalErrorType {
+    Status(StatusCode),
+    Response(RefCell<Option<FlowyResponse>>),
+}
+
+impl<T> InternalError<T> {
+    pub fn new(inner: T, status: StatusCode) -> Self {
+        InternalError {
+            inner,
+            status: InternalErrorType::Status(status),
+        }
+    }
+
+    pub fn from_response(inner: T, response: FlowyResponse) -> Self {
+        InternalError {
+            inner,
+            status: InternalErrorType::Response(RefCell::new(Some(response))),
+        }
+    }
+}
+
+impl<T> fmt::Debug for InternalError<T>
+where
+    T: fmt::Debug + 'static,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Debug::fmt(&self.inner, f)
+    }
+}
+
+impl<T> fmt::Display for InternalError<T>
+where
+    T: fmt::Display + 'static,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(&self.inner, f)
+    }
+}
+
+impl<T> HandlerError for InternalError<T>
+where
+    T: fmt::Debug + fmt::Display + 'static,
+{
+    fn status_code(&self) -> StatusCode {
+        match self.status {
+            InternalErrorType::Status(st) => st,
+            InternalErrorType::Response(ref resp) => {
+                if let Some(resp) = resp.borrow().as_ref() {
+                    resp.status.clone()
+                } else {
+                    StatusCode::Error
+                }
+            }
+        }
+    }
+
+    fn as_response(&self) -> FlowyResponse {
+        panic!()
+        // match self.status {
+        //     InternalErrorType::Status(st) => {
+        //         let mut res = Response::new(st);
+        //         let mut buf = BytesMut::new();
+        //         let _ = write!(Writer(&mut buf), "{}", self);
+        //         res.headers_mut().insert(
+        //             header::CONTENT_TYPE,
+        //             header::HeaderValue::from_static("text/plain; charset=utf-8"),
+        //         );
+        //         res.set_body(Body::from(buf))
+        //     }
+        //     InternalErrorType::Response(ref resp) => {
+        //         if let Some(resp) = resp.borrow_mut().take() {
+        //             resp
+        //         } else {
+        //             Response::new(StatusCode::INTERNAL_SERVER_ERROR)
+        //         }
+        //     }
+        // }
+    }
+}

+ 138 - 0
rust-lib/flowy-sys/src/handler/boxed.rs

@@ -0,0 +1,138 @@
+use crate::error::Error;
+use crate::payload::Payload;
+use crate::request::FlowyRequest;
+use crate::response::{FlowyResponse, Responder};
+use crate::service::{Service, ServiceFactory, ServiceRequest, ServiceResponse};
+use crate::util::ready::*;
+use futures_core::ready;
+use paste::paste;
+use pin_project::pin_project;
+use std::future::Future;
+use std::marker::PhantomData;
+use std::pin::Pin;
+use std::task::{Context, Poll};
+
+pub struct BoxServiceFactory<Cfg, Req, Res, Err, InitErr>(Inner<Cfg, Req, Res, Err, InitErr>);
+impl<C, Req, Res, Err, InitErr> ServiceFactory<Req> for BoxServiceFactory<C, Req, Res, Err, InitErr>
+where
+    Req: 'static,
+    Res: 'static,
+    Err: 'static,
+    InitErr: 'static,
+{
+    type Response = Res;
+    type Error = Err;
+    type Service = BoxService<Req, Res, Err>;
+    type InitError = InitErr;
+    type Config = C;
+
+    type Future = BoxFuture<Result<Self::Service, InitErr>>;
+
+    fn new_service(&self, cfg: C) -> Self::Future {
+        self.0.new_service(cfg)
+    }
+}
+
+pub type BoxFuture<T> = Pin<Box<dyn Future<Output = T>>>;
+pub type BoxService<Req, Res, Err> =
+    Box<dyn Service<Req, Response = Res, Error = Err, Future = BoxFuture<Result<Res, Err>>>>;
+
+pub fn service<S, Req>(service: S) -> BoxService<Req, S::Response, S::Error>
+where
+    S: Service<Req> + 'static,
+    Req: 'static,
+    S::Future: 'static,
+{
+    Box::new(ServiceWrapper::new(service))
+}
+
+impl<S, Req> Service<Req> for Box<S>
+where
+    S: Service<Req> + ?Sized,
+{
+    type Response = S::Response;
+    type Error = S::Error;
+    type Future = S::Future;
+
+    fn call(&self, request: Req) -> S::Future {
+        (**self).call(request)
+    }
+}
+
+struct ServiceWrapper<S> {
+    inner: S,
+}
+
+impl<S> ServiceWrapper<S> {
+    fn new(inner: S) -> Self {
+        Self { inner }
+    }
+}
+
+impl<S, Req, Res, Err> Service<Req> for ServiceWrapper<S>
+where
+    S: Service<Req, Response = Res, Error = Err>,
+    S::Future: 'static,
+{
+    type Response = Res;
+    type Error = Err;
+    type Future = BoxFuture<Result<Res, Err>>;
+
+    fn call(&self, req: Req) -> Self::Future {
+        Box::pin(self.inner.call(req))
+    }
+}
+
+struct FactoryWrapper<SF>(SF);
+
+impl<SF, Req, Cfg, Res, Err, InitErr> ServiceFactory<Req> for FactoryWrapper<SF>
+where
+    Req: 'static,
+    Res: 'static,
+    Err: 'static,
+    InitErr: 'static,
+    SF: ServiceFactory<Req, Config = Cfg, Response = Res, Error = Err, InitError = InitErr>,
+    SF::Future: 'static,
+    SF::Service: 'static,
+    <SF::Service as Service<Req>>::Future: 'static,
+{
+    type Response = Res;
+    type Error = Err;
+    // type Service: Service<Req, Response = Self::Response, Error = Self::Error>;
+    type Service = BoxService<Req, Res, Err>;
+    type InitError = InitErr;
+    type Config = Cfg;
+    type Future = BoxFuture<Result<Self::Service, Self::InitError>>;
+
+    fn new_service(&self, cfg: Cfg) -> Self::Future {
+        let f = self.0.new_service(cfg);
+        Box::pin(async { f.await.map(|s| Box::new(ServiceWrapper::new(s)) as _) })
+    }
+}
+
+pub fn factory<SF, Req>(
+    factory: SF,
+) -> BoxServiceFactory<SF::Config, Req, SF::Response, SF::Error, SF::InitError>
+where
+    SF: ServiceFactory<Req> + 'static,
+    Req: 'static,
+    SF::Response: 'static,
+    SF::Service: 'static,
+    SF::Future: 'static,
+    SF::Error: 'static,
+    SF::InitError: 'static,
+{
+    BoxServiceFactory(Box::new(FactoryWrapper(factory)))
+}
+
+type Inner<C, Req, Res, Err, InitErr> = Box<
+    dyn ServiceFactory<
+        Req,
+        Config = C,
+        Response = Res,
+        Error = Err,
+        InitError = InitErr,
+        Service = BoxService<Req, Res, Err>,
+        Future = BoxFuture<Result<BoxService<Req, Res, Err>, InitErr>>,
+    >,
+>;

+ 36 - 0
rust-lib/flowy-sys/src/handler/dispatch.rs

@@ -0,0 +1,36 @@
+use crate::error::Error;
+use crate::handler::{boxed, BoxServiceFactory, FromRequest, Handler, HandlerService};
+use crate::response::Responder;
+use crate::service::{ServiceRequest, ServiceResponse};
+use std::future::Future;
+
+pub struct HandlerDispatch {
+    service: BoxServiceFactory<(), ServiceRequest, ServiceResponse, Error, ()>,
+}
+
+impl HandlerDispatch {
+    pub fn new<H, T, R>(handler: H) -> Self
+    where
+        H: Handler<T, R>,
+        T: FromRequest + 'static,
+        R: Future + 'static,
+        R::Output: Responder + 'static,
+    {
+        HandlerDispatch {
+            service: boxed::factory(HandlerService::new(handler)),
+        }
+    }
+}
+
+pub fn not_found() -> String {
+    "hello".to_string()
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    #[test]
+    fn extract_string() {
+        let dispatch = HandlerDispatch::new(not_found);
+    }
+}

+ 249 - 0
rust-lib/flowy-sys/src/handler/handler.rs

@@ -0,0 +1,249 @@
+use crate::error::Error;
+use crate::payload::Payload;
+use crate::request::FlowyRequest;
+use crate::response::{FlowyResponse, Responder};
+use crate::service::{Service, ServiceFactory, ServiceRequest, ServiceResponse};
+use crate::util::ready::*;
+use futures_core::ready;
+use paste::paste;
+use pin_project::pin_project;
+use std::future::Future;
+use std::marker::PhantomData;
+use std::pin::Pin;
+use std::task::{Context, Poll};
+
+pub trait Handler<T, R>: Clone + 'static
+where
+    R: Future,
+    R::Output: Responder,
+{
+    fn call(&self, param: T) -> R;
+}
+
+pub trait FromRequest: Sized {
+    type Error: Into<Error>;
+    type Future: Future<Output = Result<Self, Self::Error>>;
+
+    fn from_request(req: &FlowyRequest, payload: &mut Payload) -> Self::Future;
+}
+
+pub struct HandlerService<H, T, R>
+where
+    H: Handler<T, R>,
+    T: FromRequest,
+    R: Future,
+    R::Output: Responder,
+{
+    handler: H,
+    _phantom: PhantomData<(T, R)>,
+}
+
+impl<H, T, R> HandlerService<H, T, R>
+where
+    H: Handler<T, R>,
+    T: FromRequest,
+    R: Future,
+    R::Output: Responder,
+{
+    pub fn new(handler: H) -> Self {
+        Self {
+            handler,
+            _phantom: PhantomData,
+        }
+    }
+}
+
+impl<H, T, R> Clone for HandlerService<H, T, R>
+where
+    H: Handler<T, R>,
+    T: FromRequest,
+    R: Future,
+    R::Output: Responder,
+{
+    fn clone(&self) -> Self {
+        Self {
+            handler: self.handler.clone(),
+            _phantom: PhantomData,
+        }
+    }
+}
+
+impl<F, T, R> ServiceFactory<ServiceRequest> for HandlerService<F, T, R>
+where
+    F: Handler<T, R>,
+    T: FromRequest,
+    R: Future,
+    R::Output: Responder,
+{
+    type Response = ServiceResponse;
+    type Error = Error;
+    type Service = Self;
+    type InitError = ();
+    type Config = ();
+    type Future = Ready<Result<Self::Service, ()>>;
+
+    fn new_service(&self, _: ()) -> Self::Future {
+        ready(Ok(self.clone()))
+    }
+}
+
+/// HandlerService is both it's ServiceFactory and Service Type.
+impl<H, T, R> Service<ServiceRequest> for HandlerService<H, T, R>
+where
+    H: Handler<T, R>,
+    T: FromRequest,
+    R: Future,
+    R::Output: Responder,
+{
+    type Response = ServiceResponse;
+    type Error = Error;
+    type Future = HandlerServiceFuture<H, T, R>;
+
+    fn call(&self, req: ServiceRequest) -> Self::Future {
+        let (req, mut payload) = req.into_parts();
+        let fut = T::from_request(&req, &mut payload);
+        HandlerServiceFuture::Extract(fut, Some(req), self.handler.clone())
+    }
+}
+
+#[pin_project(project = HandlerServiceProj)]
+pub enum HandlerServiceFuture<H, T, R>
+where
+    H: Handler<T, R>,
+    T: FromRequest,
+    R: Future,
+    R::Output: Responder,
+{
+    Extract(#[pin] T::Future, Option<FlowyRequest>, H),
+    Handle(#[pin] R, Option<FlowyRequest>),
+}
+
+impl<F, T, R> Future for HandlerServiceFuture<F, T, R>
+where
+    F: Handler<T, R>,
+    T: FromRequest,
+    R: Future,
+    R::Output: Responder,
+{
+    // Error type in this future is a placeholder type.
+    // all instances of error must be converted to ServiceResponse and return in Ok.
+    type Output = Result<ServiceResponse, Error>;
+
+    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+        loop {
+            match self.as_mut().project() {
+                HandlerServiceProj::Extract(fut, req, handle) => {
+                    match ready!(fut.poll(cx)) {
+                        Ok(item) => {
+                            let fut = handle.call(item);
+                            let state = HandlerServiceFuture::Handle(fut, req.take());
+                            self.as_mut().set(state);
+                        }
+                        Err(err) => {
+                            let req = req.take().unwrap();
+                            let res = FlowyResponse::from_error(err.into());
+                            return Poll::Ready(Ok(ServiceResponse::new(req, res)));
+                        }
+                    };
+                }
+                HandlerServiceProj::Handle(fut, req) => {
+                    let res = ready!(fut.poll(cx));
+                    let req = req.take().unwrap();
+                    let res = res.respond_to(&req);
+                    return Poll::Ready(Ok(ServiceResponse::new(req, res)));
+                }
+            }
+        }
+    }
+}
+
+macro_rules! factory_tuple ({ $($param:ident)* } => {
+    impl<Func, $($param,)* Res> Handler<($($param,)*), Res> for Func
+    where Func: Fn($($param),*) -> Res + Clone + 'static,
+          Res: Future,
+          Res::Output: Responder,
+    {
+        #[allow(non_snake_case)]
+        fn call(&self, ($($param,)*): ($($param,)*)) -> Res {
+            (self)($($param,)*)
+        }
+    }
+});
+
+macro_rules! tuple_from_req ({$tuple_type:ident, $(($n:tt, $T:ident)),+} => {
+    #[allow(non_snake_case)]
+    mod $tuple_type {
+        use super::*;
+
+        #[pin_project::pin_project]
+        struct FromRequestFutures<$($T: FromRequest),+>($(#[pin] $T::Future),+);
+
+        /// FromRequest implementation for tuple
+        #[doc(hidden)]
+        #[allow(unused_parens)]
+        impl<$($T: FromRequest + 'static),+> FromRequest for ($($T,)+)
+        {
+            type Error = Error;
+            type Future = $tuple_type<$($T),+>;
+
+            fn from_request(req: &FlowyRequest, payload: &mut Payload) -> Self::Future {
+                $tuple_type {
+                    items: <($(Option<$T>,)+)>::default(),
+                    futs: FromRequestFutures($($T::from_request(req, payload),)+),
+                }
+            }
+        }
+
+        #[doc(hidden)]
+        #[pin_project::pin_project]
+        pub struct $tuple_type<$($T: FromRequest),+> {
+            items: ($(Option<$T>,)+),
+            #[pin]
+            futs: FromRequestFutures<$($T,)+>,
+        }
+
+        impl<$($T: FromRequest),+> Future for $tuple_type<$($T),+>
+        {
+            type Output = Result<($($T,)+), Error>;
+
+            fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+                let mut this = self.project();
+                let mut ready = true;
+                $(
+                    if this.items.$n.is_none() {
+                        match this.futs.as_mut().project().$n.poll(cx) {
+                            Poll::Ready(Ok(item)) => this.items.$n = Some(item),
+                            Poll::Pending => ready = false,
+                            Poll::Ready(Err(e)) => return Poll::Ready(Err(e.into())),
+                        }
+                    }
+                )+
+
+                if ready {
+                    Poll::Ready(Ok(
+                        ($(this.items.$n.take().unwrap(),)+)
+                    ))
+                } else {
+                    Poll::Pending
+                }
+            }
+        }
+    }
+});
+
+factory_tuple! {}
+factory_tuple! { A }
+factory_tuple! { A B }
+factory_tuple! { A B C }
+factory_tuple! { A B C D }
+factory_tuple! { A B C D E }
+
+#[rustfmt::skip]
+mod m {
+    use super::*;
+    tuple_from_req!(TupleFromRequest1, (0, A));
+    tuple_from_req!(TupleFromRequest2, (0, A), (1, B));
+    tuple_from_req!(TupleFromRequest3, (0, A), (1, B), (2, C));
+    tuple_from_req!(TupleFromRequest4, (0, A), (1, B), (2, C), (3, D));
+    tuple_from_req!(TupleFromRequest5, (0, A), (1, B), (2, C), (3, D), (4, E));
+}

+ 7 - 0
rust-lib/flowy-sys/src/handler/mod.rs

@@ -0,0 +1,7 @@
+mod boxed;
+mod dispatch;
+mod handler;
+
+pub use boxed::*;
+pub use dispatch::*;
+pub use handler::*;

+ 7 - 0
rust-lib/flowy-sys/src/lib.rs

@@ -0,0 +1,7 @@
+mod error;
+mod handler;
+mod payload;
+mod request;
+mod response;
+mod service;
+mod util;

+ 12 - 0
rust-lib/flowy-sys/src/payload.rs

@@ -0,0 +1,12 @@
+use std::pin::Pin;
+
+use bytes::Bytes;
+use futures::Stream;
+
+pub enum PayloadError {}
+
+pub type PayloadStream = Pin<Box<dyn Stream<Item = Result<Bytes, PayloadError>>>>;
+pub enum Payload<S = PayloadStream> {
+    None,
+    Stream(S),
+}

+ 3 - 0
rust-lib/flowy-sys/src/request/mod.rs

@@ -0,0 +1,3 @@
+mod request;
+
+pub use request::*;

+ 1 - 0
rust-lib/flowy-sys/src/request/request.rs

@@ -0,0 +1 @@
+pub struct FlowyRequest {}

+ 47 - 0
rust-lib/flowy-sys/src/response/builder.rs

@@ -0,0 +1,47 @@
+use crate::error::Error;
+use crate::response::{FlowyResponse, ResponseData, StatusCode};
+
+macro_rules! static_response {
+    ($name:ident, $status:expr) => {
+        #[allow(non_snake_case, missing_docs)]
+        pub fn $name() -> FlowyResponseBuilder {
+            FlowyResponseBuilder::new($status)
+        }
+    };
+}
+
+pub struct FlowyResponseBuilder<T = ResponseData> {
+    pub data: T,
+    pub status: StatusCode,
+    pub error: Option<Error>,
+}
+
+impl FlowyResponseBuilder {
+    pub fn new(status: StatusCode) -> Self {
+        FlowyResponseBuilder {
+            data: ResponseData::None,
+            status,
+            error: None,
+        }
+    }
+
+    pub fn data<D: std::convert::Into<ResponseData>>(mut self, data: D) -> Self {
+        self.data = data.into();
+        self
+    }
+
+    pub fn error(mut self, error: Option<Error>) -> Self {
+        self.error = error;
+        self
+    }
+
+    pub fn build(self) -> FlowyResponse {
+        FlowyResponse {
+            data: self.data,
+            status: self.status,
+            error: self.error,
+        }
+    }
+
+    static_response!(Ok, StatusCode::Success);
+}

+ 7 - 0
rust-lib/flowy-sys/src/response/mod.rs

@@ -0,0 +1,7 @@
+mod builder;
+mod responder;
+mod response;
+
+pub use builder::*;
+pub use responder::*;
+pub use response::*;

+ 20 - 0
rust-lib/flowy-sys/src/response/responder.rs

@@ -0,0 +1,20 @@
+use crate::request::FlowyRequest;
+use crate::response::FlowyResponse;
+use crate::response::FlowyResponseBuilder;
+
+pub trait Responder {
+    fn respond_to(self, req: &FlowyRequest) -> FlowyResponse;
+}
+
+macro_rules! impl_responder {
+    ($res: ty) => {
+        impl Responder for $res {
+            fn respond_to(self, _: &FlowyRequest) -> FlowyResponse {
+                FlowyResponseBuilder::Ok().data(self).build()
+            }
+        }
+    };
+}
+
+impl_responder!(&'static str);
+impl_responder!(String);

+ 66 - 0
rust-lib/flowy-sys/src/response/response.rs

@@ -0,0 +1,66 @@
+use crate::error::Error;
+use crate::request::FlowyRequest;
+use crate::response::FlowyResponseBuilder;
+use crate::response::Responder;
+use std::future::Future;
+
+#[derive(Clone, Copy)]
+pub enum StatusCode {
+    Success,
+    Error,
+}
+
+pub enum ResponseData {
+    Bytes(Vec<u8>),
+    None,
+}
+
+pub struct FlowyResponse<T = ResponseData> {
+    pub data: T,
+    pub status: StatusCode,
+    pub error: Option<Error>,
+}
+
+impl FlowyResponse {
+    pub fn new(status: StatusCode) -> Self {
+        FlowyResponse {
+            data: ResponseData::None,
+            status,
+            error: None,
+        }
+    }
+
+    pub fn success() -> Self {
+        FlowyResponse {
+            data: ResponseData::None,
+            status: StatusCode::Success,
+            error: None,
+        }
+    }
+
+    #[inline]
+    pub fn from_error(error: Error) -> FlowyResponse {
+        let mut resp = error.as_handler_error().as_response();
+        resp.error = Some(error);
+        resp
+    }
+}
+
+impl Responder for FlowyResponse {
+    #[inline]
+    fn respond_to(self, _: &FlowyRequest) -> FlowyResponse {
+        self
+    }
+}
+
+impl std::convert::Into<ResponseData> for String {
+    fn into(self) -> ResponseData {
+        ResponseData::Bytes(self.into_bytes())
+    }
+}
+
+impl std::convert::Into<ResponseData> for &str {
+    fn into(self) -> ResponseData {
+        self.to_string().into()
+    }
+}

+ 46 - 0
rust-lib/flowy-sys/src/service.rs

@@ -0,0 +1,46 @@
+use crate::payload::Payload;
+use crate::request::FlowyRequest;
+use crate::response::{FlowyResponse, Responder, ResponseData};
+use std::future::Future;
+
+pub trait Service<Request> {
+    type Response;
+    type Error;
+    type Future: Future<Output = Result<Self::Response, Self::Error>>;
+
+    fn call(&self, req: Request) -> Self::Future;
+}
+
+pub trait ServiceFactory<Req> {
+    type Response;
+    type Error;
+    type Service: Service<Req, Response = Self::Response, Error = Self::Error>;
+    type InitError;
+    type Config;
+    type Future: Future<Output = Result<Self::Service, Self::InitError>>;
+
+    fn new_service(&self, cfg: Self::Config) -> Self::Future;
+}
+
+pub struct ServiceRequest {
+    req: FlowyRequest,
+    payload: Payload,
+}
+
+impl ServiceRequest {
+    #[inline]
+    pub fn into_parts(self) -> (FlowyRequest, Payload) {
+        (self.req, self.payload)
+    }
+}
+
+pub struct ServiceResponse<T = ResponseData> {
+    request: FlowyRequest,
+    response: FlowyResponse<T>,
+}
+
+impl<T> ServiceResponse<T> {
+    pub fn new(request: FlowyRequest, response: FlowyResponse<T>) -> Self {
+        ServiceResponse { request, response }
+    }
+}

+ 1 - 0
rust-lib/flowy-sys/src/util/mod.rs

@@ -0,0 +1 @@
+pub mod ready;

+ 30 - 0
rust-lib/flowy-sys/src/util/ready.rs

@@ -0,0 +1,30 @@
+use std::future::Future;
+use std::pin::Pin;
+use std::task::{Context, Poll};
+
+pub struct Ready<T> {
+    val: Option<T>,
+}
+
+impl<T> Ready<T> {
+    #[inline]
+    pub fn into_inner(mut self) -> T {
+        self.val.take().unwrap()
+    }
+}
+
+impl<T> Unpin for Ready<T> {}
+
+impl<T> Future for Ready<T> {
+    type Output = T;
+
+    #[inline]
+    fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<T> {
+        let val = self.val.take().expect("Ready polled after completion");
+        Poll::Ready(val)
+    }
+}
+
+pub fn ready<T>(val: T) -> Ready<T> {
+    Ready { val: Some(val) }
+}

+ 3 - 0
rust-lib/rust-toolchain

@@ -0,0 +1,3 @@
+[toolchain]
+channel = "nightly-2021-04-24"
+targets = [ "aarch64-apple-darwin", "x86_64-apple-darwin", "aarch64-apple-ios", "x86_64-apple-ios" ]

+ 17 - 0
rust-lib/rustfmt.toml

@@ -0,0 +1,17 @@
+# https://rust-lang.github.io/rustfmt/?version=master&search=
+max_width = 120
+tab_spaces = 4
+fn_single_line = true
+match_block_trailing_comma = true
+normalize_comments = true
+wrap_comments = true
+merge_imports = true
+reorder_impl_items = true
+use_field_init_shorthand = true
+use_try_shorthand = true
+normalize_doc_attributes = true
+report_todo = "Always"
+report_fixme = "Always"
+imports_layout = "HorizontalVertical"
+enum_discrim_align_threshold = 20
+edition = "2018"