mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
add flowy-sys crate
This commit is contained in:
parent
126ac20ccc
commit
4d91ed147d
3
.gitignore
vendored
3
.gitignore
vendored
@ -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,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" />
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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
rust-lib/.gitignore
vendored
Normal file
10
rust-lib/.gitignore
vendored
Normal file
@ -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
rust-lib/Cargo.toml
Normal file
7
rust-lib/Cargo.toml
Normal file
@ -0,0 +1,7 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"flowy-sys",
|
||||
]
|
||||
|
||||
[profile.dev]
|
||||
split-debuginfo = "unpacked"
|
15
rust-lib/flowy-sys/Cargo.toml
Normal file
15
rust-lib/flowy-sys/Cargo.toml
Normal file
@ -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
rust-lib/flowy-sys/src/error.rs
Normal file
150
rust-lib/flowy-sys/src/error.rs
Normal file
@ -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
rust-lib/flowy-sys/src/handler/boxed.rs
Normal file
138
rust-lib/flowy-sys/src/handler/boxed.rs
Normal file
@ -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
rust-lib/flowy-sys/src/handler/dispatch.rs
Normal file
36
rust-lib/flowy-sys/src/handler/dispatch.rs
Normal file
@ -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
rust-lib/flowy-sys/src/handler/handler.rs
Normal file
249
rust-lib/flowy-sys/src/handler/handler.rs
Normal file
@ -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
rust-lib/flowy-sys/src/handler/mod.rs
Normal file
7
rust-lib/flowy-sys/src/handler/mod.rs
Normal file
@ -0,0 +1,7 @@
|
||||
mod boxed;
|
||||
mod dispatch;
|
||||
mod handler;
|
||||
|
||||
pub use boxed::*;
|
||||
pub use dispatch::*;
|
||||
pub use handler::*;
|
7
rust-lib/flowy-sys/src/lib.rs
Normal file
7
rust-lib/flowy-sys/src/lib.rs
Normal file
@ -0,0 +1,7 @@
|
||||
mod error;
|
||||
mod handler;
|
||||
mod payload;
|
||||
mod request;
|
||||
mod response;
|
||||
mod service;
|
||||
mod util;
|
12
rust-lib/flowy-sys/src/payload.rs
Normal file
12
rust-lib/flowy-sys/src/payload.rs
Normal file
@ -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
rust-lib/flowy-sys/src/request/mod.rs
Normal file
3
rust-lib/flowy-sys/src/request/mod.rs
Normal file
@ -0,0 +1,3 @@
|
||||
mod request;
|
||||
|
||||
pub use request::*;
|
1
rust-lib/flowy-sys/src/request/request.rs
Normal file
1
rust-lib/flowy-sys/src/request/request.rs
Normal file
@ -0,0 +1 @@
|
||||
pub struct FlowyRequest {}
|
47
rust-lib/flowy-sys/src/response/builder.rs
Normal file
47
rust-lib/flowy-sys/src/response/builder.rs
Normal file
@ -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
rust-lib/flowy-sys/src/response/mod.rs
Normal file
7
rust-lib/flowy-sys/src/response/mod.rs
Normal file
@ -0,0 +1,7 @@
|
||||
mod builder;
|
||||
mod responder;
|
||||
mod response;
|
||||
|
||||
pub use builder::*;
|
||||
pub use responder::*;
|
||||
pub use response::*;
|
20
rust-lib/flowy-sys/src/response/responder.rs
Normal file
20
rust-lib/flowy-sys/src/response/responder.rs
Normal file
@ -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
rust-lib/flowy-sys/src/response/response.rs
Normal file
66
rust-lib/flowy-sys/src/response/response.rs
Normal file
@ -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
rust-lib/flowy-sys/src/service.rs
Normal file
46
rust-lib/flowy-sys/src/service.rs
Normal file
@ -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
rust-lib/flowy-sys/src/util/mod.rs
Normal file
1
rust-lib/flowy-sys/src/util/mod.rs
Normal file
@ -0,0 +1 @@
|
||||
pub mod ready;
|
30
rust-lib/flowy-sys/src/util/ready.rs
Normal file
30
rust-lib/flowy-sys/src/util/ready.rs
Normal file
@ -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
rust-lib/rust-toolchain
Normal file
3
rust-lib/rust-toolchain
Normal file
@ -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
rust-lib/rustfmt.toml
Normal file
17
rust-lib/rustfmt.toml
Normal file
@ -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"
|
Loading…
Reference in New Issue
Block a user