add flowy-sys crate

This commit is contained in:
appflowy 2021-06-24 16:32:36 +08:00
parent 126ac20ccc
commit 4d91ed147d
25 changed files with 904 additions and 3 deletions

3
.gitignore vendored
View File

@ -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

View File

@ -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" />

View File

@ -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.

View File

@ -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
View 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
View File

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

View 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"

View 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)
// }
// }
// }
}
}

View 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>>,
>,
>;

View 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);
}
}

View 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));
}

View File

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

View File

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

View 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),
}

View File

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

View File

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

View 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);
}

View File

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

View 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);

View 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()
}
}

View 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 }
}
}

View File

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

View 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
View 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
View 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"