1
0
mirror of https://github.com/fafhrd91/actix-net synced 2024-11-27 18:02:58 +01:00

update doc strings

This commit is contained in:
Nikolay Kim 2019-12-10 21:11:39 +06:00
parent 1d810b4561
commit 7163e2c2a2
8 changed files with 185 additions and 9 deletions

View File

@ -7,7 +7,6 @@
//! [`AsyncRead`]: # //! [`AsyncRead`]: #
//! [`AsyncWrite`]: # //! [`AsyncWrite`]: #
#![deny(rust_2018_idioms, warnings)] #![deny(rust_2018_idioms, warnings)]
#![allow(clippy::type_complexity)]
mod bcodec; mod bcodec;
mod framed; mod framed;

View File

@ -2,14 +2,13 @@
name = "actix-service" name = "actix-service"
version = "1.0.0-alpha.4" version = "1.0.0-alpha.4"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"] authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix Service" description = "Actix service"
keywords = ["network", "framework", "async", "futures"] keywords = ["network", "framework", "async", "futures"]
homepage = "https://actix.rs" homepage = "https://actix.rs"
repository = "https://github.com/actix/actix-net.git" repository = "https://github.com/actix/actix-net.git"
documentation = "https://docs.rs/actix-service/" documentation = "https://docs.rs/actix-service/"
categories = ["network-programming", "asynchronous"] categories = ["network-programming", "asynchronous"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
exclude = [".gitignore", ".travis.yml", ".cargo/config", "appveyor.yml"]
edition = "2018" edition = "2018"
workspace = ".." workspace = ".."

View File

@ -18,6 +18,41 @@ where
} }
/// Create `ServiceFactory` for function that can produce services /// Create `ServiceFactory` for function that can produce services
///
/// # Example
///
/// ```rust
/// use std::io;
/// use actix_service::{fn_factory, fn_service, Service, ServiceFactory};
/// use futures_util::future::ok;
///
/// /// Service that divides two usize values.
/// async fn div((x, y): (usize, usize)) -> Result<usize, io::Error> {
/// if y == 0 {
/// Err(io::Error::new(io::ErrorKind::Other, "divide by zdro"))
/// } else {
/// Ok(x / y)
/// }
/// }
///
/// #[actix_rt::main]
/// async fn main() -> io::Result<()> {
/// // Create service factory that produces `div` services
/// let factory = fn_factory(|| {
/// ok::<_, io::Error>(fn_service(div))
/// });
///
/// // construct new service
/// let mut srv = factory.new_service(()).await?;
///
/// // now we can use `div` service
/// let result = srv.call((10, 20)).await?;
///
/// println!("10 / 20 = {}", result);
///
/// Ok(())
/// }
/// ```
pub fn fn_factory<F, Cfg, Srv, Fut, Err>(f: F) -> FnServiceNoConfig<F, Cfg, Srv, Fut, Err> pub fn fn_factory<F, Cfg, Srv, Fut, Err>(f: F) -> FnServiceNoConfig<F, Cfg, Srv, Fut, Err>
where where
Srv: Service, Srv: Service,
@ -27,7 +62,36 @@ where
FnServiceNoConfig::new(f) FnServiceNoConfig::new(f)
} }
/// Create `ServiceFactory` for function that accepts config and can produce services /// Create `ServiceFactory` for function that accepts config argument and can produce services
///
/// Any function that has following form `Fn(Config) -> Future<Output = Service>` could
/// act as a `ServiceFactory`.
///
/// # Example
///
/// ```rust
/// use std::io;
/// use actix_service::{fn_factory_with_config, fn_service, Service, ServiceFactory};
/// use futures_util::future::ok;
///
/// #[actix_rt::main]
/// async fn main() -> io::Result<()> {
/// // Create service factory. factory uses config argument for
/// // services it generates.
/// let factory = fn_factory_with_config(|y: usize| {
/// ok::<_, io::Error>(fn_service(move |x: usize| ok::<_, io::Error>(x * y)))
/// });
///
/// // construct new service with config argument
/// let mut srv = factory.new_service(10).await?;
///
/// let result = srv.call(10).await?;
/// assert_eq!(result, 100);
///
/// println!("10 * 10 = {}", result);
/// Ok(())
/// }
/// ```
pub fn fn_factory_with_config<F, Fut, Cfg, Srv, Err>( pub fn fn_factory_with_config<F, Fut, Cfg, Srv, Err>(
f: F, f: F,
) -> FnServiceConfig<F, Fut, Cfg, Srv, Err> ) -> FnServiceConfig<F, Fut, Cfg, Srv, Err>

View File

@ -31,6 +31,42 @@ pub use self::pipeline::{pipeline, pipeline_factory, Pipeline, PipelineFactory};
pub use self::transform::{apply, Transform}; pub use self::transform::{apply, Transform};
/// An asynchronous function from `Request` to a `Response`. /// An asynchronous function from `Request` to a `Response`.
///
/// `Service` represents a service that represanting interation, taking requests and giving back
/// replies. You can think about service as a function with one argument and result as a return
/// type. In general form it looks like `async fn(Req) -> Result<Res, Err>`. `Service`
/// trait just generalizing form of this function. Each parameter described as an assotiated type.
///
/// Services provides a symmetric and uniform API, same abstractions represents
/// clients and servers. Services describe only `transforamtion` operation
/// which encorouge to simplify api surface and phrases `value transformation`.
/// That leads to simplier design of each service. That also allows better testability
/// and better composition.
///
/// Services could be represented in several different forms. In general,
/// Service is a type that implements `Service` trait.
///
/// ```rust,ignore
/// struct MyService;
///
/// impl Service for MyService {
/// type Request = u8;
/// type Response = u64;
/// type Error = MyError;
/// type Future = Pin<Box<Future<Output=Result<Self::Response, Self::Error>>>;
///
/// fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { ... }
///
/// fn call(&mut self) -> Self::Future { ... }
/// }
/// ```
///
/// Service can have mutable state that influence computation.
/// This service could be rewritten as a simple function:
///
/// ```rust,ignore
/// async fn my_service(req: u8) -> Result<u64, MyError>;
/// ```
pub trait Service { pub trait Service {
/// Requests handled by the service. /// Requests handled by the service.
type Request; type Request;
@ -53,6 +89,12 @@ pub trait Service {
/// This is a **best effort** implementation. False positives are permitted. /// This is a **best effort** implementation. False positives are permitted.
/// It is permitted for the service to return `Ready` from a `poll_ready` /// It is permitted for the service to return `Ready` from a `poll_ready`
/// call and the next invocation of `call` results in an error. /// call and the next invocation of `call` results in an error.
///
/// There are several notes to consider:
///
/// 1. `.poll_ready()` might be called on different task from actual service call.
///
/// 2. In case of chained services, `.poll_ready()` get called for all services at once.
fn poll_ready(&mut self, ctx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>>; fn poll_ready(&mut self, ctx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>>;
/// Process the request and return the response asynchronously. /// Process the request and return the response asynchronously.
@ -287,7 +329,7 @@ pub trait IntoServiceFactory<T>
where where
T: ServiceFactory, T: ServiceFactory,
{ {
/// Convert `Self` an `ServiceFactory` /// Convert `Self` to a `ServiceFactory`
fn into_factory(self) -> T; fn into_factory(self) -> T;
} }

View File

@ -2,7 +2,10 @@ use std::marker::PhantomData;
use super::ServiceFactory; use super::ServiceFactory;
/// Adapt external config to a config for provided new service /// Adapt external config argument to a config for provided service factory
///
/// Note that this function consumes the receiving service factory and returns
/// a wrapped version of it.
pub fn map_config<T, F, C>(factory: T, f: F) -> MapConfig<T, F, C> pub fn map_config<T, F, C>(factory: T, f: F) -> MapConfig<T, F, C>
where where
T: ServiceFactory, T: ServiceFactory,

View File

@ -9,6 +9,7 @@ use crate::map_init_err::MapInitErr;
use crate::then::{ThenService, ThenServiceFactory}; use crate::then::{ThenService, ThenServiceFactory};
use crate::{IntoService, IntoServiceFactory, Service, ServiceFactory}; use crate::{IntoService, IntoServiceFactory, Service, ServiceFactory};
/// Contruct new pipeline with one service in pipeline chain.
pub fn pipeline<F, T>(service: F) -> Pipeline<T> pub fn pipeline<F, T>(service: F) -> Pipeline<T>
where where
F: IntoService<T>, F: IntoService<T>,
@ -19,6 +20,7 @@ where
} }
} }
/// Contruct new pipeline factory with one service factory.
pub fn pipeline_factory<T, F>(factory: F) -> PipelineFactory<T> pub fn pipeline_factory<T, F>(factory: F) -> PipelineFactory<T>
where where
T: ServiceFactory, T: ServiceFactory,

View File

@ -19,11 +19,78 @@ where
ApplyTransform::new(t, service.into_factory()) ApplyTransform::new(t, service.into_factory())
} }
/// The `Transform` trait defines the interface of a service factory that wraps inner service
/// during construction.
///
/// Transform(middleware) wraps inner service and runs during
/// inbound and/or outbound processing in the request/response lifecycle.
/// It may modify request and/or response.
///
/// For example, timeout transform:
///
/// ```rust,ignore
/// pub struct Timeout<S> {
/// service: S,
/// timeout: Duration,
/// }
///
/// impl<S> Service for Timeout<S>
/// where
/// S: Service,
/// {
/// type Request = S::Request;
/// type Response = S::Response;
/// type Error = TimeoutError<S::Error>;
/// type Future = TimeoutServiceResponse<S>;
///
/// fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
/// ready!(self.service.poll_ready(cx)).map_err(TimeoutError::Service)
/// }
///
/// fn call(&mut self, req: S::Request) -> Self::Future {
/// TimeoutServiceResponse {
/// fut: self.service.call(req),
/// sleep: Delay::new(clock::now() + self.timeout),
/// }
/// }
/// }
/// ```
///
/// Timeout service in above example is decoupled from underlying service implementation
/// and could be applied to any service.
///
/// The `Transform` trait defines the interface of a Service factory. `Transform` /// The `Transform` trait defines the interface of a Service factory. `Transform`
/// is often implemented for middleware, defining how to construct a /// is often implemented for middleware, defining how to construct a
/// middleware Service. A Service that is constructed by the factory takes /// middleware Service. A Service that is constructed by the factory takes
/// the Service that follows it during execution as a parameter, assuming /// the Service that follows it during execution as a parameter, assuming
/// ownership of the next Service. /// ownership of the next Service.
///
/// Factory for `Timeout` middleware from the above example could look like this:
///
/// ```rust,,ignore
/// pub struct TimeoutTransform {
/// timeout: Duration,
/// }
///
/// impl<S> Transform<S> for TimeoutTransform<E>
/// where
/// S: Service,
/// {
/// type Request = S::Request;
/// type Response = S::Response;
/// type Error = TimeoutError<S::Error>;
/// type InitError = S::Error;
/// type Transform = Timeout<S>;
/// type Future = Ready<Result<Self::Transform, Self::InitError>>;
///
/// fn new_transform(&self, service: S) -> Self::Future {
/// ok(TimeoutService {
/// service,
/// timeout: self.timeout,
/// })
/// }
/// }
/// ```
pub trait Transform<S> { pub trait Transform<S> {
/// Requests handled by the service. /// Requests handled by the service.
type Request; type Request;
@ -41,13 +108,13 @@ pub trait Transform<S> {
Error = Self::Error, Error = Self::Error,
>; >;
/// Errors produced while building a service. /// Errors produced while building a transform service.
type InitError; type InitError;
/// The future response value. /// The future response value.
type Future: Future<Output = Result<Self::Transform, Self::InitError>>; type Future: Future<Output = Result<Self::Transform, Self::InitError>>;
/// Creates and returns a new Service component, asynchronously /// Creates and returns a new Transform component, asynchronously
fn new_transform(&self, service: S) -> Self::Future; fn new_transform(&self, service: S) -> Self::Future;
/// Map this transforms's factory error to a different error, /// Map this transforms's factory error to a different error,

View File

@ -3,7 +3,7 @@ use std::marker::PhantomData;
use std::pin::Pin; use std::pin::Pin;
use std::task::{Context, Poll}; use std::task::{Context, Poll};
pub use open_ssl::ssl::{SslAcceptor, SslAcceptorBuilder, AlpnError}; pub use open_ssl::ssl::{AlpnError, SslAcceptor, SslAcceptorBuilder};
pub use tokio_openssl::{HandshakeError, SslStream}; pub use tokio_openssl::{HandshakeError, SslStream};
use actix_codec::{AsyncRead, AsyncWrite}; use actix_codec::{AsyncRead, AsyncWrite};