mirror of
https://github.com/Noratrieb/101844-repro.git
synced 2026-01-15 14:45:02 +01:00
tower lol
This commit is contained in:
parent
1e415960ec
commit
40a6bd3bce
49 changed files with 4626 additions and 1 deletions
30
tower/tower-layer/CHANGELOG.md
Normal file
30
tower/tower-layer/CHANGELOG.md
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# 0.3.1 (January 7, 2021)
|
||||
|
||||
### Added
|
||||
|
||||
- Added `layer_fn`, for constructing a `Layer` from a function taking
|
||||
a `Service` and returning a different `Service` ([#491])
|
||||
- Added an implementation of `Layer` for `&Layer` ([#446])
|
||||
- Multiple documentation improvements ([#487], [#490])
|
||||
|
||||
[#491]: https://github.com/tower-rs/tower/pull/491
|
||||
[#446]: https://github.com/tower-rs/tower/pull/446
|
||||
[#487]: https://github.com/tower-rs/tower/pull/487
|
||||
[#490]: https://github.com/tower-rs/tower/pull/490
|
||||
|
||||
# 0.3.0 (November 29, 2019)
|
||||
|
||||
- Move layer builder from `tower-util` to tower-layer.
|
||||
|
||||
# 0.3.0-alpha.2 (September 30, 2019)
|
||||
|
||||
- Move to `futures-*-preview 0.3.0-alpha.19`
|
||||
- Move to `pin-project 0.4`
|
||||
|
||||
# 0.3.0-alpha.1 (September 11, 2019)
|
||||
|
||||
- Move to `std::future`
|
||||
|
||||
# 0.1.0 (April 26, 2019)
|
||||
|
||||
- Initial release
|
||||
26
tower/tower-layer/Cargo.toml
Normal file
26
tower/tower-layer/Cargo.toml
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
[package]
|
||||
name = "tower-layer"
|
||||
# When releasing to crates.io:
|
||||
# - Update doc url
|
||||
# - Cargo.toml
|
||||
# - README.md
|
||||
# - Update CHANGELOG.md.
|
||||
# - Create "v0.1.x" git tag.
|
||||
version = "0.3.1"
|
||||
authors = ["Tower Maintainers <team@tower-rs.com>"]
|
||||
license = "MIT"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/tower-rs/tower"
|
||||
homepage = "https://github.com/tower-rs/tower"
|
||||
documentation = "https://docs.rs/tower-layer/0.3.0-alpha.2"
|
||||
description = """
|
||||
Decorates a `Service` to allow easy composition between `Service`s.
|
||||
"""
|
||||
categories = ["asynchronous", "network-programming"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
|
||||
[dev-dependencies]
|
||||
tower-service = { version = "0.3.0", path = "../tower-service" }
|
||||
tower = { version = "0.4", path = "../tower" }
|
||||
25
tower/tower-layer/LICENSE
Normal file
25
tower/tower-layer/LICENSE
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
Copyright (c) 2019 Tower Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
43
tower/tower-layer/README.md
Normal file
43
tower/tower-layer/README.md
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
# Tower Layer
|
||||
|
||||
Decorates a [Tower] `Service`, transforming either the request or the response.
|
||||
|
||||
[![Crates.io][crates-badge]][crates-url]
|
||||
[![Documentation][docs-badge]][docs-url]
|
||||
[![Documentation (master)][docs-master-badge]][docs-master-url]
|
||||
[![MIT licensed][mit-badge]][mit-url]
|
||||
[![Build Status][actions-badge]][actions-url]
|
||||
[![Discord chat][discord-badge]][discord-url]
|
||||
|
||||
[crates-badge]: https://img.shields.io/crates/v/tower-layer.svg
|
||||
[crates-url]: https://crates.io/crates/tower-layer
|
||||
[docs-badge]: https://docs.rs/tower-layer/badge.svg
|
||||
[docs-url]: https://docs.rs/tower-layer
|
||||
[docs-master-badge]: https://img.shields.io/badge/docs-master-blue
|
||||
[docs-master-url]: https://tower-rs.github.io/tower/tower_layer
|
||||
[mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg
|
||||
[mit-url]: LICENSE
|
||||
[actions-badge]: https://github.com/tower-rs/tower/workflows/CI/badge.svg
|
||||
[actions-url]:https://github.com/tower-rs/tower/actions?query=workflow%3ACI
|
||||
[discord-badge]: https://img.shields.io/discord/500028886025895936?logo=discord&label=discord&logoColor=white
|
||||
[discord-url]: https://discord.gg/EeF3cQw
|
||||
|
||||
## Overview
|
||||
|
||||
Often, many of the pieces needed for writing network applications can be
|
||||
reused across multiple services. The `Layer` trait can be used to write
|
||||
reusable components that can be applied to very different kinds of services;
|
||||
for example, it can be applied to services operating on different protocols,
|
||||
and to both the client and server side of a network transaction.
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the [MIT license](LICENSE).
|
||||
|
||||
### Contribution
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||
for inclusion in Tower by you, shall be licensed as MIT, without any additional
|
||||
terms or conditions.
|
||||
|
||||
[Tower]: https://crates.io/crates/tower
|
||||
37
tower/tower-layer/src/identity.rs
Normal file
37
tower/tower-layer/src/identity.rs
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
use super::Layer;
|
||||
use std::fmt;
|
||||
|
||||
/// A no-op middleware.
|
||||
///
|
||||
/// When wrapping a [`Service`], the [`Identity`] layer returns the provided
|
||||
/// service without modifying it.
|
||||
///
|
||||
/// [`Service`]: https://docs.rs/tower-service/latest/tower_service/trait.Service.html
|
||||
#[derive(Default, Clone)]
|
||||
pub struct Identity {
|
||||
_p: (),
|
||||
}
|
||||
|
||||
impl Identity {
|
||||
/// Create a new [`Identity`] value
|
||||
pub fn new() -> Identity {
|
||||
Identity { _p: () }
|
||||
}
|
||||
}
|
||||
|
||||
/// Decorates a [`Service`], transforming either the request or the response.
|
||||
///
|
||||
/// [`Service`]: https://docs.rs/tower-service/latest/tower_service/trait.Service.html
|
||||
impl<S> Layer<S> for Identity {
|
||||
type Service = S;
|
||||
|
||||
fn layer(&self, inner: S) -> Self::Service {
|
||||
inner
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Identity {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Identity").finish()
|
||||
}
|
||||
}
|
||||
114
tower/tower-layer/src/layer_fn.rs
Normal file
114
tower/tower-layer/src/layer_fn.rs
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
use super::Layer;
|
||||
use std::fmt;
|
||||
|
||||
/// Returns a new [`LayerFn`] that implements [`Layer`] by calling the
|
||||
/// given function.
|
||||
///
|
||||
/// The [`Layer::layer`] method takes a type implementing [`Service`] and
|
||||
/// returns a different type implementing [`Service`]. In many cases, this can
|
||||
/// be implemented by a function or a closure. The [`LayerFn`] helper allows
|
||||
/// writing simple [`Layer`] implementations without needing the boilerplate of
|
||||
/// a new struct implementing [`Layer`].
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// # use tower::Service;
|
||||
/// # use std::task::{Poll, Context};
|
||||
/// # use tower_layer::{Layer, layer_fn};
|
||||
/// # use std::fmt;
|
||||
/// # use std::convert::Infallible;
|
||||
/// #
|
||||
/// // A middleware that logs requests before forwarding them to another service
|
||||
/// pub struct LogService<S> {
|
||||
/// target: &'static str,
|
||||
/// service: S,
|
||||
/// }
|
||||
///
|
||||
/// impl<S, Request> Service<Request> for LogService<S>
|
||||
/// where
|
||||
/// S: Service<Request>,
|
||||
/// Request: fmt::Debug,
|
||||
/// {
|
||||
/// type Response = S::Response;
|
||||
/// type Error = S::Error;
|
||||
/// type Future = S::Future;
|
||||
///
|
||||
/// fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
/// self.service.poll_ready(cx)
|
||||
/// }
|
||||
///
|
||||
/// fn call(&mut self, request: Request) -> Self::Future {
|
||||
/// // Log the request
|
||||
/// println!("request = {:?}, target = {:?}", request, self.target);
|
||||
///
|
||||
/// self.service.call(request)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // A `Layer` that wraps services in `LogService`
|
||||
/// let log_layer = layer_fn(|service| {
|
||||
/// LogService {
|
||||
/// service,
|
||||
/// target: "tower-docs",
|
||||
/// }
|
||||
/// });
|
||||
///
|
||||
/// // An example service. This one uppercases strings
|
||||
/// let uppercase_service = tower::service_fn(|request: String| async move {
|
||||
/// Ok::<_, Infallible>(request.to_uppercase())
|
||||
/// });
|
||||
///
|
||||
/// // Wrap our service in a `LogService` so requests are logged.
|
||||
/// let wrapped_service = log_layer.layer(uppercase_service);
|
||||
/// ```
|
||||
///
|
||||
/// [`Service`]: https://docs.rs/tower-service/latest/tower_service/trait.Service.html
|
||||
/// [`Layer::layer`]: crate::Layer::layer
|
||||
pub fn layer_fn<T>(f: T) -> LayerFn<T> {
|
||||
LayerFn { f }
|
||||
}
|
||||
|
||||
/// A `Layer` implemented by a closure. See the docs for [`layer_fn`] for more details.
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct LayerFn<F> {
|
||||
f: F,
|
||||
}
|
||||
|
||||
impl<F, S, Out> Layer<S> for LayerFn<F>
|
||||
where
|
||||
F: Fn(S) -> Out,
|
||||
{
|
||||
type Service = Out;
|
||||
|
||||
fn layer(&self, inner: S) -> Self::Service {
|
||||
(self.f)(inner)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> fmt::Debug for LayerFn<F> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("LayerFn")
|
||||
.field("f", &format_args!("{}", std::any::type_name::<F>()))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[test]
|
||||
fn layer_fn_has_useful_debug_impl() {
|
||||
struct WrappedService<S> {
|
||||
inner: S,
|
||||
}
|
||||
let layer = layer_fn(|svc| WrappedService { inner: svc });
|
||||
let _svc = layer.layer("foo");
|
||||
|
||||
assert_eq!(
|
||||
"LayerFn { f: tower_layer::layer_fn::tests::layer_fn_has_useful_debug_impl::{{closure}} }".to_string(),
|
||||
format!("{:?}", layer),
|
||||
);
|
||||
}
|
||||
}
|
||||
111
tower/tower-layer/src/lib.rs
Normal file
111
tower/tower-layer/src/lib.rs
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
#![warn(
|
||||
missing_debug_implementations,
|
||||
missing_docs,
|
||||
rust_2018_idioms,
|
||||
unreachable_pub
|
||||
)]
|
||||
#![forbid(unsafe_code)]
|
||||
// `rustdoc::broken_intra_doc_links` is checked on CI
|
||||
|
||||
//! Layer traits and extensions.
|
||||
//!
|
||||
//! A layer decorates an service and provides additional functionality. It
|
||||
//! allows other services to be composed with the service that implements layer.
|
||||
//!
|
||||
//! A middleware implements the [`Layer`] and [`Service`] trait.
|
||||
//!
|
||||
//! [`Service`]: https://docs.rs/tower/latest/tower/trait.Service.html
|
||||
|
||||
mod identity;
|
||||
mod layer_fn;
|
||||
mod stack;
|
||||
|
||||
pub use self::{
|
||||
identity::Identity,
|
||||
layer_fn::{layer_fn, LayerFn},
|
||||
stack::Stack,
|
||||
};
|
||||
|
||||
/// Decorates a [`Service`], transforming either the request or the response.
|
||||
///
|
||||
/// Often, many of the pieces needed for writing network applications can be
|
||||
/// reused across multiple services. The `Layer` trait can be used to write
|
||||
/// reusable components that can be applied to very different kinds of services;
|
||||
/// for example, it can be applied to services operating on different protocols,
|
||||
/// and to both the client and server side of a network transaction.
|
||||
///
|
||||
/// # Log
|
||||
///
|
||||
/// Take request logging as an example:
|
||||
///
|
||||
/// ```rust
|
||||
/// # use tower_service::Service;
|
||||
/// # use std::task::{Poll, Context};
|
||||
/// # use tower_layer::Layer;
|
||||
/// # use std::fmt;
|
||||
///
|
||||
/// pub struct LogLayer {
|
||||
/// target: &'static str,
|
||||
/// }
|
||||
///
|
||||
/// impl<S> Layer<S> for LogLayer {
|
||||
/// type Service = LogService<S>;
|
||||
///
|
||||
/// fn layer(&self, service: S) -> Self::Service {
|
||||
/// LogService {
|
||||
/// target: self.target,
|
||||
/// service
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // This service implements the Log behavior
|
||||
/// pub struct LogService<S> {
|
||||
/// target: &'static str,
|
||||
/// service: S,
|
||||
/// }
|
||||
///
|
||||
/// impl<S, Request> Service<Request> for LogService<S>
|
||||
/// where
|
||||
/// S: Service<Request>,
|
||||
/// Request: fmt::Debug,
|
||||
/// {
|
||||
/// type Response = S::Response;
|
||||
/// type Error = S::Error;
|
||||
/// type Future = S::Future;
|
||||
///
|
||||
/// fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
||||
/// self.service.poll_ready(cx)
|
||||
/// }
|
||||
///
|
||||
/// fn call(&mut self, request: Request) -> Self::Future {
|
||||
/// // Insert log statement here or other functionality
|
||||
/// println!("request = {:?}, target = {:?}", request, self.target);
|
||||
/// self.service.call(request)
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The above log implementation is decoupled from the underlying protocol and
|
||||
/// is also decoupled from client or server concerns. In other words, the same
|
||||
/// log middleware could be used in either a client or a server.
|
||||
///
|
||||
/// [`Service`]: https://docs.rs/tower/latest/tower/trait.Service.html
|
||||
pub trait Layer<S> {
|
||||
/// The wrapped service
|
||||
type Service;
|
||||
/// Wrap the given service with the middleware, returning a new service
|
||||
/// that has been decorated with the middleware.
|
||||
fn layer(&self, inner: S) -> Self::Service;
|
||||
}
|
||||
|
||||
impl<'a, T, S> Layer<S> for &'a T
|
||||
where
|
||||
T: ?Sized + Layer<S>,
|
||||
{
|
||||
type Service = T::Service;
|
||||
|
||||
fn layer(&self, inner: S) -> Self::Service {
|
||||
(**self).layer(inner)
|
||||
}
|
||||
}
|
||||
62
tower/tower-layer/src/stack.rs
Normal file
62
tower/tower-layer/src/stack.rs
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
use super::Layer;
|
||||
use std::fmt;
|
||||
|
||||
/// Two middlewares chained together.
|
||||
#[derive(Clone)]
|
||||
pub struct Stack<Inner, Outer> {
|
||||
inner: Inner,
|
||||
outer: Outer,
|
||||
}
|
||||
|
||||
impl<Inner, Outer> Stack<Inner, Outer> {
|
||||
/// Create a new `Stack`.
|
||||
pub fn new(inner: Inner, outer: Outer) -> Self {
|
||||
Stack { inner, outer }
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, Inner, Outer> Layer<S> for Stack<Inner, Outer>
|
||||
where
|
||||
Inner: Layer<S>,
|
||||
Outer: Layer<Inner::Service>,
|
||||
{
|
||||
type Service = Outer::Service;
|
||||
|
||||
fn layer(&self, service: S) -> Self::Service {
|
||||
let inner = self.inner.layer(service);
|
||||
|
||||
self.outer.layer(inner)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Inner, Outer> fmt::Debug for Stack<Inner, Outer>
|
||||
where
|
||||
Inner: fmt::Debug,
|
||||
Outer: fmt::Debug,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// The generated output of nested `Stack`s is very noisy and makes
|
||||
// it harder to understand what is in a `ServiceBuilder`.
|
||||
//
|
||||
// Instead, this output is designed assuming that a `Stack` is
|
||||
// usually quite nested, and inside a `ServiceBuilder`. Therefore,
|
||||
// this skips using `f.debug_struct()`, since each one would force
|
||||
// a new layer of indentation.
|
||||
//
|
||||
// - In compact mode, a nested stack ends up just looking like a flat
|
||||
// list of layers.
|
||||
//
|
||||
// - In pretty mode, while a newline is inserted between each layer,
|
||||
// the `DebugStruct` used in the `ServiceBuilder` will inject padding
|
||||
// to that each line is at the same indentation level.
|
||||
//
|
||||
// Also, the order of [outer, inner] is important, since it reflects
|
||||
// the order that the layers were added to the stack.
|
||||
if f.alternate() {
|
||||
// pretty
|
||||
write!(f, "{:#?},\n{:#?}", self.outer, self.inner)
|
||||
} else {
|
||||
write!(f, "{:?}, {:?}", self.outer, self.inner)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue