├── .github └── workflows │ ├── CI.yml │ ├── patch.toml │ ├── publish.yml │ └── release.yml ├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── deny.toml ├── examples └── Cargo.toml ├── guides ├── README.md └── building-a-middleware-from-scratch.md ├── netlify.toml ├── tower-layer ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md └── src │ ├── identity.rs │ ├── layer_fn.rs │ ├── lib.rs │ ├── stack.rs │ └── tuple.rs ├── tower-service ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md └── src │ └── lib.rs ├── tower-test ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md ├── src │ ├── lib.rs │ ├── macros.rs │ └── mock │ │ ├── error.rs │ │ ├── future.rs │ │ ├── mod.rs │ │ └── spawn.rs └── tests │ └── mock.rs └── tower ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md ├── examples └── tower-balance.rs ├── src ├── balance │ ├── error.rs │ ├── mod.rs │ └── p2c │ │ ├── layer.rs │ │ ├── make.rs │ │ ├── mod.rs │ │ ├── service.rs │ │ └── test.rs ├── buffer │ ├── error.rs │ ├── future.rs │ ├── layer.rs │ ├── message.rs │ ├── mod.rs │ ├── service.rs │ └── worker.rs ├── builder │ └── mod.rs ├── discover │ ├── list.rs │ └── mod.rs ├── filter │ ├── future.rs │ ├── layer.rs │ ├── mod.rs │ └── predicate.rs ├── hedge │ ├── delay.rs │ ├── latency.rs │ ├── mod.rs │ ├── rotating_histogram.rs │ └── select.rs ├── layer.rs ├── lib.rs ├── limit │ ├── concurrency │ │ ├── future.rs │ │ ├── layer.rs │ │ ├── mod.rs │ │ └── service.rs │ ├── mod.rs │ └── rate │ │ ├── layer.rs │ │ ├── mod.rs │ │ ├── rate.rs │ │ └── service.rs ├── load │ ├── completion.rs │ ├── constant.rs │ ├── mod.rs │ ├── peak_ewma.rs │ └── pending_requests.rs ├── load_shed │ ├── error.rs │ ├── future.rs │ ├── layer.rs │ └── mod.rs ├── macros.rs ├── make │ ├── make_connection.rs │ ├── make_service.rs │ ├── make_service │ │ └── shared.rs │ └── mod.rs ├── ready_cache │ ├── cache.rs │ ├── error.rs │ └── mod.rs ├── reconnect │ ├── future.rs │ └── mod.rs ├── retry │ ├── backoff.rs │ ├── budget │ │ ├── mod.rs │ │ └── tps_budget.rs │ ├── future.rs │ ├── layer.rs │ ├── mod.rs │ └── policy.rs ├── spawn_ready │ ├── future.rs │ ├── layer.rs │ ├── mod.rs │ └── service.rs ├── steer │ └── mod.rs ├── timeout │ ├── error.rs │ ├── future.rs │ ├── layer.rs │ └── mod.rs └── util │ ├── and_then.rs │ ├── boxed │ ├── layer.rs │ ├── layer_clone.rs │ ├── layer_clone_sync.rs │ ├── mod.rs │ ├── sync.rs │ └── unsync.rs │ ├── boxed_clone.rs │ ├── boxed_clone_sync.rs │ ├── call_all │ ├── common.rs │ ├── mod.rs │ ├── ordered.rs │ └── unordered.rs │ ├── either.rs │ ├── future_service.rs │ ├── map_err.rs │ ├── map_future.rs │ ├── map_request.rs │ ├── map_response.rs │ ├── map_result.rs │ ├── mod.rs │ ├── oneshot.rs │ ├── optional │ ├── error.rs │ ├── future.rs │ └── mod.rs │ ├── ready.rs │ ├── rng.rs │ ├── service_fn.rs │ └── then.rs └── tests ├── balance └── main.rs ├── buffer └── main.rs ├── builder.rs ├── filter └── async_filter.rs ├── hedge └── main.rs ├── limit ├── concurrency.rs ├── main.rs └── rate.rs ├── load_shed └── main.rs ├── ready_cache └── main.rs ├── retry └── main.rs ├── spawn_ready └── main.rs ├── steer └── main.rs ├── support.rs └── util ├── call_all.rs ├── main.rs ├── oneshot.rs └── service_fn.rs /.github/workflows/CI.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: {} 8 | 9 | env: 10 | MSRV: 1.64.0 11 | 12 | jobs: 13 | check-stable: 14 | # Run `cargo check` first to ensure that the pushed code at least compiles. 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v4 18 | - uses: dtolnay/rust-toolchain@stable 19 | - name: Check 20 | run: cargo check --workspace --all-features --all-targets 21 | 22 | check-docs: 23 | runs-on: ubuntu-latest 24 | steps: 25 | - uses: actions/checkout@v4 26 | - uses: dtolnay/rust-toolchain@stable 27 | - name: cargo doc 28 | working-directory: ${{ matrix.subcrate }} 29 | env: 30 | RUSTDOCFLAGS: "-D rustdoc::broken_intra_doc_links" 31 | run: cargo doc --all-features --no-deps 32 | 33 | check-msrv: 34 | runs-on: ubuntu-latest 35 | steps: 36 | - uses: actions/checkout@v4 37 | - name: "install Rust ${{ env.MSRV }}" 38 | uses: dtolnay/rust-toolchain@master 39 | with: 40 | toolchain: ${{ env.MSRV }} 41 | - name: "install Rust nightly" 42 | uses: dtolnay/rust-toolchain@nightly 43 | - name: Select minimal versions 44 | run: cargo update -Z minimal-versions 45 | - name: Check 46 | run: | 47 | rustup default ${{ env.MSRV }} 48 | cargo check --all --all-targets --all-features --locked 49 | 50 | cargo-hack: 51 | runs-on: ubuntu-latest 52 | steps: 53 | - uses: actions/checkout@v4 54 | - uses: dtolnay/rust-toolchain@stable 55 | - name: install cargo-hack 56 | uses: taiki-e/install-action@cargo-hack 57 | - name: cargo hack check 58 | working-directory: ${{ matrix.subcrate }} 59 | run: cargo hack check --each-feature --no-dev-deps --workspace 60 | 61 | test-versions: 62 | # Test against the stable, beta, and nightly Rust toolchains on ubuntu-latest. 63 | needs: check-stable 64 | runs-on: ubuntu-latest 65 | strategy: 66 | # Disable fail-fast. If the test run for a particular Rust version fails, 67 | # don't cancel the other test runs, so that we can determine whether a 68 | # failure only occurs on a particular version. 69 | fail-fast: false 70 | matrix: 71 | rust: [stable, beta, nightly] 72 | steps: 73 | - uses: actions/checkout@v4 74 | - name: "install Rust ${{ matrix.rust }}" 75 | uses: dtolnay/rust-toolchain@master 76 | with: 77 | toolchain: ${{ matrix.rust }} 78 | - name: Run tests 79 | run: cargo test --workspace --all-features 80 | 81 | test-msrv: 82 | needs: check-msrv 83 | runs-on: ubuntu-latest 84 | steps: 85 | - uses: actions/checkout@v4 86 | - name: "install Rust ${{ env.MSRV }}" 87 | uses: dtolnay/rust-toolchain@master 88 | with: 89 | toolchain: ${{ env.MSRV }} 90 | - name: "install Rust nightly" 91 | uses: dtolnay/rust-toolchain@nightly 92 | - name: Select minimal versions 93 | run: cargo update -Z minimal-versions 94 | - name: test 95 | run: | 96 | rustup default ${{ env.MSRV }} 97 | cargo check --workspace --all-features --locked 98 | 99 | style: 100 | needs: check-stable 101 | runs-on: ubuntu-latest 102 | steps: 103 | - uses: actions/checkout@v4 104 | - uses: dtolnay/rust-toolchain@stable 105 | with: 106 | components: rustfmt 107 | - name: rustfmt 108 | run: cargo fmt --all -- --check 109 | 110 | deny-check: 111 | name: cargo-deny check 112 | runs-on: ubuntu-latest 113 | steps: 114 | - uses: actions/checkout@v4 115 | - uses: EmbarkStudios/cargo-deny-action@v1 116 | with: 117 | command: check 118 | -------------------------------------------------------------------------------- /.github/workflows/patch.toml: -------------------------------------------------------------------------------- 1 | # Patch dependencies to run all tests against versions of the crate in the 2 | # repository. 3 | [patch.crates-io] 4 | tower = { path = "tower" } 5 | tower-layer = { path = "tower-layer" } 6 | tower-service = { path = "tower-service" } 7 | tower-test = { path = "tower-test" } 8 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Deploy API Documentation 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | publish: 10 | 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - name: Checkout code 15 | uses: actions/checkout@v4 16 | - name: Install nightly Rust 17 | uses: dtolnay/rust-toolchain@master 18 | with: 19 | toolchain: nightly 20 | - name: Generate documentation 21 | run: cargo doc --workspace --no-deps --all-features 22 | env: 23 | # Enable the RustDoc `#[doc(cfg(...))]` attribute. 24 | RUSTDOCFLAGS: --cfg docsrs 25 | - name: Deploy documentation 26 | if: success() 27 | uses: crazy-max/ghaction-github-pages@v1 28 | with: 29 | target_branch: gh-pages 30 | build_dir: target/doc 31 | env: 32 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 33 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: create github release 2 | 3 | on: 4 | push: 5 | tags: 6 | - tower-[0-9]+.* 7 | - tower-[a-z]+-[0-9]+.* 8 | 9 | jobs: 10 | create-release: 11 | name: Create GitHub release 12 | # only publish from the origin repository 13 | if: github.repository_owner == 'tower-rs' 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | - uses: taiki-e/create-gh-release-action@v1.3.0 18 | with: 19 | prefix: "(tower)|(tower-[a-z]+)" 20 | changelog: "$prefix/CHANGELOG.md" 21 | title: "$prefix $version" 22 | branch: "(master)|(v[0-9]+.[0-9]+.x)" 23 | env: 24 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | 3 | members = [ 4 | "tower", 5 | "tower-layer", 6 | "tower-service", 7 | "tower-test", 8 | ] 9 | 10 | [workspace.dependencies] 11 | futures = "0.3.22" 12 | futures-core = "0.3.22" 13 | futures-util = { version = "0.3.22", default-features = false } 14 | hdrhistogram = { version = "7.0", default-features = false } 15 | http = "1" 16 | indexmap = "2.0.2" 17 | lazy_static = "1.4.0" 18 | pin-project-lite = "0.2.7" 19 | quickcheck = "1" 20 | rand = "0.8" 21 | slab = "0.4" 22 | sync_wrapper = "1" 23 | tokio = "1.6.2" 24 | tokio-stream = "0.1.0" 25 | tokio-test = "0.4" 26 | tokio-util = { version = "0.7.0", default-features = false } 27 | tracing = { version = "0.1.2", default-features = false } 28 | tracing-subscriber = { version = "0.3", default-features = false } 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Tower Contributors 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tower 2 | 3 | Tower is a library of modular and reusable components for building robust 4 | networking clients and servers. 5 | 6 | [![Crates.io][crates-badge]][crates-url] 7 | [![Documentation][docs-badge]][docs-url] 8 | [![Documentation (master)][docs-master-badge]][docs-master-url] 9 | [![MIT licensed][mit-badge]][mit-url] 10 | [![Build Status][actions-badge]][actions-url] 11 | [![Discord chat][discord-badge]][discord-url] 12 | 13 | [crates-badge]: https://img.shields.io/crates/v/tower.svg 14 | [crates-url]: https://crates.io/crates/tower 15 | [docs-badge]: https://docs.rs/tower/badge.svg 16 | [docs-url]: https://docs.rs/tower 17 | [docs-master-badge]: https://img.shields.io/badge/docs-master-blue 18 | [docs-master-url]: https://tower-rs.github.io/tower/tower 19 | [mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg 20 | [mit-url]: LICENSE 21 | [actions-badge]: https://github.com/tower-rs/tower/workflows/CI/badge.svg 22 | [actions-url]:https://github.com/tower-rs/tower/actions?query=workflow%3ACI 23 | [discord-badge]: https://img.shields.io/discord/500028886025895936?logo=discord&label=discord&logoColor=white 24 | [discord-url]: https://discord.gg/EeF3cQw 25 | 26 | ## Overview 27 | 28 | Tower aims to make it as easy as possible to build robust networking clients and 29 | servers. It is protocol agnostic, but is designed around a request / response 30 | pattern. If your protocol is entirely stream based, Tower may not be a good fit. 31 | 32 | ## Supported Rust Versions 33 | 34 | Tower will keep a rolling MSRV (minimum supported Rust version) policy of **at 35 | least** 6 months. When increasing the MSRV, the new Rust version must have been 36 | released at least six months ago. The current MSRV is 1.64.0. 37 | 38 | ## `no_std` 39 | 40 | `tower` itself is _not_ `no_std` compatible, but `tower-layer` and `tower-service` are. 41 | 42 | ## Getting Started 43 | 44 | If you're brand new to Tower and want to start with the basics we recommend you 45 | check out some of our [guides]. 46 | 47 | ## License 48 | 49 | This project is licensed under the [MIT license](LICENSE). 50 | 51 | ### Contribution 52 | 53 | Unless you explicitly state otherwise, any contribution intentionally submitted 54 | for inclusion in Tower by you, shall be licensed as MIT, without any additional 55 | terms or conditions. 56 | 57 | [guides]: https://github.com/tower-rs/tower/tree/master/guides 58 | -------------------------------------------------------------------------------- /deny.toml: -------------------------------------------------------------------------------- 1 | [advisories] 2 | vulnerability = "deny" 3 | unmaintained = "warn" 4 | notice = "warn" 5 | 6 | [licenses] 7 | unlicensed = "deny" 8 | allow = [] 9 | deny = [] 10 | copyleft = "warn" 11 | allow-osi-fsf-free = "either" 12 | confidence-threshold = 0.8 13 | 14 | [bans] 15 | multiple-versions = "deny" 16 | highlight = "all" 17 | skip = [] 18 | 19 | [sources] 20 | unknown-registry = "warn" 21 | unknown-git = "warn" 22 | allow-git = [] 23 | -------------------------------------------------------------------------------- /examples/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "examples" 3 | version = "0.0.0" 4 | publish = false 5 | edition = "2018" 6 | 7 | # If you copy one of the examples into a new project, you should be using 8 | # [dependencies] instead. 9 | [dev-dependencies] 10 | tower = { version = "0.4", path = "../tower", features = ["full"] } 11 | tower-service = "0.3" 12 | tokio = { version = "1.0", features = ["full"] } 13 | rand = "0.8" 14 | pin-project = "1.0" 15 | futures = "0.3.22" 16 | tracing = "0.1" 17 | tracing-subscriber = "0.2" 18 | hdrhistogram = "7" 19 | 20 | [[example]] 21 | name = "balance" 22 | path = "balance.rs" 23 | -------------------------------------------------------------------------------- /guides/README.md: -------------------------------------------------------------------------------- 1 | # Tower Guides 2 | 3 | These guides are meant to be an introduction to Tower. At least basic Rust 4 | experience is assumed. Some experience with asynchronous Rust is also 5 | recommended. If you're brand new to async Rust, we recommend the [Asynchronous 6 | Programming in Rust][async-book] book or the [Tokio tutorial][tokio-tutorial]. 7 | 8 | Additionally, some of these guides explain Tower from the perspective of HTTP 9 | servers and clients. However, Tower is useful for any network protocol that 10 | follows an async request/response pattern. HTTP is used here because it is a 11 | widely known protocol, and one of Tower's more common use-cases. 12 | 13 | ## Guides 14 | 15 | - ["Inventing the `Service` trait"][invent] walks through how Tower's 16 | fundamental [`Service`] trait could be designed from scratch. If you have no 17 | experience with Tower and want to learn the absolute basics, this is where you 18 | should start. 19 | - ["Building a middleware from scratch"][build] walks through how to build the 20 | [`Timeout`] middleware as it exists in Tower today, without taking any shortcuts. 21 | 22 | [async-book]: https://rust-lang.github.io/async-book/ 23 | [tokio-tutorial]: https://tokio.rs/tokio/tutorial 24 | [invent]: https://tokio.rs/blog/2021-05-14-inventing-the-service-trait 25 | [build]: https://github.com/tower-rs/tower/blob/master/guides/building-a-middleware-from-scratch.md 26 | [`Service`]: https://docs.rs/tower/latest/tower/trait.Service.html 27 | [`Timeout`]: https://docs.rs/tower/latest/tower/timeout/struct.Timeout.html 28 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | command = "rustup install nightly --profile minimal && cargo doc --features=full --no-deps && cp -r target/doc _netlify_out" 3 | environment = { RUSTDOCFLAGS= "--cfg docsrs" } 4 | publish = "_netlify_out" 5 | 6 | [[redirects]] 7 | from = "/" 8 | to = "/tower" -------------------------------------------------------------------------------- /tower-layer/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.3.3 (August 1, 2024) 2 | 3 | ### Added 4 | 5 | - **builder,util**: add convenience methods for boxing services ([#616]) 6 | - **all**: new functions const when possible ([#760]) 7 | 8 | [#616]: https://github.com/tower-rs/tower/pull/616 9 | [#760]: https://github.com/tower-rs/tower/pull/760 10 | 11 | # 0.3.2 (Octpber 10, 2022) 12 | 13 | ## Added 14 | 15 | - Implement `Layer` for tuples of up to 16 elements ([#694]) 16 | 17 | [#694]: https://github.com/tower-rs/tower/pull/694 18 | 19 | # 0.3.1 (January 7, 2021) 20 | 21 | ### Added 22 | 23 | - Added `layer_fn`, for constructing a `Layer` from a function taking 24 | a `Service` and returning a different `Service` ([#491]) 25 | - Added an implementation of `Layer` for `&Layer` ([#446]) 26 | - Multiple documentation improvements ([#487], [#490]) 27 | 28 | [#491]: https://github.com/tower-rs/tower/pull/491 29 | [#446]: https://github.com/tower-rs/tower/pull/446 30 | [#487]: https://github.com/tower-rs/tower/pull/487 31 | [#490]: https://github.com/tower-rs/tower/pull/490 32 | 33 | # 0.3.0 (November 29, 2019) 34 | 35 | - Move layer builder from `tower-util` to tower-layer. 36 | 37 | # 0.3.0-alpha.2 (September 30, 2019) 38 | 39 | - Move to `futures-*-preview 0.3.0-alpha.19` 40 | - Move to `pin-project 0.4` 41 | 42 | # 0.3.0-alpha.1 (September 11, 2019) 43 | 44 | - Move to `std::future` 45 | 46 | # 0.1.0 (April 26, 2019) 47 | 48 | - Initial release 49 | -------------------------------------------------------------------------------- /tower-layer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tower-layer" 3 | # When releasing to crates.io: 4 | # - Update doc url 5 | # - Cargo.toml 6 | # - README.md 7 | # - Update CHANGELOG.md. 8 | # - Create "v0.1.x" git tag. 9 | version = "0.3.3" 10 | authors = ["Tower Maintainers "] 11 | license = "MIT" 12 | readme = "README.md" 13 | repository = "https://github.com/tower-rs/tower" 14 | homepage = "https://github.com/tower-rs/tower" 15 | documentation = "https://docs.rs/tower-layer/0.3.3" 16 | description = """ 17 | Decorates a `Service` to allow easy composition between `Service`s. 18 | """ 19 | categories = ["asynchronous", "network-programming"] 20 | edition = "2018" 21 | 22 | [dependencies] 23 | 24 | [dev-dependencies] 25 | tower-service = { path = "../tower-service" } 26 | tower = { path = "../tower" } 27 | -------------------------------------------------------------------------------- /tower-layer/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Tower Contributors 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /tower-layer/README.md: -------------------------------------------------------------------------------- 1 | # Tower Layer 2 | 3 | Decorates a [Tower] `Service`, transforming either the request or the response. 4 | 5 | [![Crates.io][crates-badge]][crates-url] 6 | [![Documentation][docs-badge]][docs-url] 7 | [![Documentation (master)][docs-master-badge]][docs-master-url] 8 | [![MIT licensed][mit-badge]][mit-url] 9 | [![Build Status][actions-badge]][actions-url] 10 | [![Discord chat][discord-badge]][discord-url] 11 | 12 | [crates-badge]: https://img.shields.io/crates/v/tower-layer.svg 13 | [crates-url]: https://crates.io/crates/tower-layer 14 | [docs-badge]: https://docs.rs/tower-layer/badge.svg 15 | [docs-url]: https://docs.rs/tower-layer 16 | [docs-master-badge]: https://img.shields.io/badge/docs-master-blue 17 | [docs-master-url]: https://tower-rs.github.io/tower/tower_layer 18 | [mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg 19 | [mit-url]: LICENSE 20 | [actions-badge]: https://github.com/tower-rs/tower/workflows/CI/badge.svg 21 | [actions-url]:https://github.com/tower-rs/tower/actions?query=workflow%3ACI 22 | [discord-badge]: https://img.shields.io/discord/500028886025895936?logo=discord&label=discord&logoColor=white 23 | [discord-url]: https://discord.gg/EeF3cQw 24 | 25 | ## Overview 26 | 27 | Often, many of the pieces needed for writing network applications can be 28 | reused across multiple services. The `Layer` trait can be used to write 29 | reusable components that can be applied to very different kinds of services; 30 | for example, it can be applied to services operating on different protocols, 31 | and to both the client and server side of a network transaction. 32 | 33 | `tower-layer` is `no_std` compatible. 34 | 35 | ## License 36 | 37 | This project is licensed under the [MIT license](LICENSE). 38 | 39 | ### Contribution 40 | 41 | Unless you explicitly state otherwise, any contribution intentionally submitted 42 | for inclusion in Tower by you, shall be licensed as MIT, without any additional 43 | terms or conditions. 44 | 45 | [Tower]: https://crates.io/crates/tower 46 | -------------------------------------------------------------------------------- /tower-layer/src/identity.rs: -------------------------------------------------------------------------------- 1 | use super::Layer; 2 | use core::fmt; 3 | 4 | /// A no-op middleware. 5 | /// 6 | /// When wrapping a [`Service`], the [`Identity`] layer returns the provided 7 | /// service without modifying it. 8 | /// 9 | /// [`Service`]: https://docs.rs/tower-service/latest/tower_service/trait.Service.html 10 | #[derive(Default, Clone)] 11 | pub struct Identity { 12 | _p: (), 13 | } 14 | 15 | impl Identity { 16 | /// Create a new [`Identity`] value 17 | pub const fn new() -> Identity { 18 | Identity { _p: () } 19 | } 20 | } 21 | 22 | /// Decorates a [`Service`], transforming either the request or the response. 23 | /// 24 | /// [`Service`]: https://docs.rs/tower-service/latest/tower_service/trait.Service.html 25 | impl Layer for Identity { 26 | type Service = S; 27 | 28 | fn layer(&self, inner: S) -> Self::Service { 29 | inner 30 | } 31 | } 32 | 33 | impl fmt::Debug for Identity { 34 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 35 | f.debug_struct("Identity").finish() 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tower-layer/src/layer_fn.rs: -------------------------------------------------------------------------------- 1 | use super::Layer; 2 | use core::fmt; 3 | 4 | /// Returns a new [`LayerFn`] that implements [`Layer`] by calling the 5 | /// given function. 6 | /// 7 | /// The [`Layer::layer`] method takes a type implementing [`Service`] and 8 | /// returns a different type implementing [`Service`]. In many cases, this can 9 | /// be implemented by a function or a closure. The [`LayerFn`] helper allows 10 | /// writing simple [`Layer`] implementations without needing the boilerplate of 11 | /// a new struct implementing [`Layer`]. 12 | /// 13 | /// # Example 14 | /// ```rust 15 | /// # use tower::Service; 16 | /// # use core::task::{Poll, Context}; 17 | /// # use tower_layer::{Layer, layer_fn}; 18 | /// # use core::fmt; 19 | /// # use core::convert::Infallible; 20 | /// # 21 | /// // A middleware that logs requests before forwarding them to another service 22 | /// pub struct LogService { 23 | /// target: &'static str, 24 | /// service: S, 25 | /// } 26 | /// 27 | /// impl Service for LogService 28 | /// where 29 | /// S: Service, 30 | /// Request: fmt::Debug, 31 | /// { 32 | /// type Response = S::Response; 33 | /// type Error = S::Error; 34 | /// type Future = S::Future; 35 | /// 36 | /// fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { 37 | /// self.service.poll_ready(cx) 38 | /// } 39 | /// 40 | /// fn call(&mut self, request: Request) -> Self::Future { 41 | /// // Log the request 42 | /// println!("request = {:?}, target = {:?}", request, self.target); 43 | /// 44 | /// self.service.call(request) 45 | /// } 46 | /// } 47 | /// 48 | /// // A `Layer` that wraps services in `LogService` 49 | /// let log_layer = layer_fn(|service| { 50 | /// LogService { 51 | /// service, 52 | /// target: "tower-docs", 53 | /// } 54 | /// }); 55 | /// 56 | /// // An example service. This one uppercases strings 57 | /// let uppercase_service = tower::service_fn(|request: String| async move { 58 | /// Ok::<_, Infallible>(request.to_uppercase()) 59 | /// }); 60 | /// 61 | /// // Wrap our service in a `LogService` so requests are logged. 62 | /// let wrapped_service = log_layer.layer(uppercase_service); 63 | /// ``` 64 | /// 65 | /// [`Service`]: https://docs.rs/tower-service/latest/tower_service/trait.Service.html 66 | /// [`Layer::layer`]: crate::Layer::layer 67 | pub fn layer_fn(f: T) -> LayerFn { 68 | LayerFn { f } 69 | } 70 | 71 | /// A `Layer` implemented by a closure. See the docs for [`layer_fn`] for more details. 72 | #[derive(Clone, Copy)] 73 | pub struct LayerFn { 74 | f: F, 75 | } 76 | 77 | impl Layer for LayerFn 78 | where 79 | F: Fn(S) -> Out, 80 | { 81 | type Service = Out; 82 | 83 | fn layer(&self, inner: S) -> Self::Service { 84 | (self.f)(inner) 85 | } 86 | } 87 | 88 | impl fmt::Debug for LayerFn { 89 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 90 | f.debug_struct("LayerFn") 91 | .field("f", &format_args!("{}", core::any::type_name::())) 92 | .finish() 93 | } 94 | } 95 | 96 | #[cfg(test)] 97 | mod tests { 98 | use super::*; 99 | use alloc::{format, string::ToString}; 100 | 101 | #[allow(dead_code)] 102 | #[test] 103 | fn layer_fn_has_useful_debug_impl() { 104 | struct WrappedService { 105 | inner: S, 106 | } 107 | let layer = layer_fn(|svc| WrappedService { inner: svc }); 108 | let _svc = layer.layer("foo"); 109 | 110 | assert_eq!( 111 | "LayerFn { f: tower_layer::layer_fn::tests::layer_fn_has_useful_debug_impl::{{closure}} }".to_string(), 112 | format!("{:?}", layer), 113 | ); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /tower-layer/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![warn( 2 | missing_debug_implementations, 3 | missing_docs, 4 | rust_2018_idioms, 5 | unreachable_pub 6 | )] 7 | #![forbid(unsafe_code)] 8 | // `rustdoc::broken_intra_doc_links` is checked on CI 9 | 10 | //! Layer traits and extensions. 11 | //! 12 | //! A layer decorates an service and provides additional functionality. It 13 | //! allows other services to be composed with the service that implements layer. 14 | //! 15 | //! A middleware implements the [`Layer`] and [`Service`] trait. 16 | //! 17 | //! [`Service`]: https://docs.rs/tower/*/tower/trait.Service.html 18 | 19 | #![no_std] 20 | 21 | #[cfg(test)] 22 | extern crate alloc; 23 | 24 | mod identity; 25 | mod layer_fn; 26 | mod stack; 27 | mod tuple; 28 | 29 | pub use self::{ 30 | identity::Identity, 31 | layer_fn::{layer_fn, LayerFn}, 32 | stack::Stack, 33 | }; 34 | 35 | /// Decorates a [`Service`], transforming either the request or the response. 36 | /// 37 | /// Often, many of the pieces needed for writing network applications can be 38 | /// reused across multiple services. The `Layer` trait can be used to write 39 | /// reusable components that can be applied to very different kinds of services; 40 | /// for example, it can be applied to services operating on different protocols, 41 | /// and to both the client and server side of a network transaction. 42 | /// 43 | /// # Log 44 | /// 45 | /// Take request logging as an example: 46 | /// 47 | /// ```rust 48 | /// # use tower_service::Service; 49 | /// # use core::task::{Poll, Context}; 50 | /// # use tower_layer::Layer; 51 | /// # use core::fmt; 52 | /// 53 | /// pub struct LogLayer { 54 | /// target: &'static str, 55 | /// } 56 | /// 57 | /// impl Layer for LogLayer { 58 | /// type Service = LogService; 59 | /// 60 | /// fn layer(&self, service: S) -> Self::Service { 61 | /// LogService { 62 | /// target: self.target, 63 | /// service 64 | /// } 65 | /// } 66 | /// } 67 | /// 68 | /// // This service implements the Log behavior 69 | /// pub struct LogService { 70 | /// target: &'static str, 71 | /// service: S, 72 | /// } 73 | /// 74 | /// impl Service for LogService 75 | /// where 76 | /// S: Service, 77 | /// Request: fmt::Debug, 78 | /// { 79 | /// type Response = S::Response; 80 | /// type Error = S::Error; 81 | /// type Future = S::Future; 82 | /// 83 | /// fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { 84 | /// self.service.poll_ready(cx) 85 | /// } 86 | /// 87 | /// fn call(&mut self, request: Request) -> Self::Future { 88 | /// // Insert log statement here or other functionality 89 | /// println!("request = {:?}, target = {:?}", request, self.target); 90 | /// self.service.call(request) 91 | /// } 92 | /// } 93 | /// ``` 94 | /// 95 | /// The above log implementation is decoupled from the underlying protocol and 96 | /// is also decoupled from client or server concerns. In other words, the same 97 | /// log middleware could be used in either a client or a server. 98 | /// 99 | /// [`Service`]: https://docs.rs/tower/*/tower/trait.Service.html 100 | pub trait Layer { 101 | /// The wrapped service 102 | type Service; 103 | /// Wrap the given service with the middleware, returning a new service 104 | /// that has been decorated with the middleware. 105 | fn layer(&self, inner: S) -> Self::Service; 106 | } 107 | 108 | impl<'a, T, S> Layer for &'a T 109 | where 110 | T: ?Sized + Layer, 111 | { 112 | type Service = T::Service; 113 | 114 | fn layer(&self, inner: S) -> Self::Service { 115 | (**self).layer(inner) 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /tower-layer/src/stack.rs: -------------------------------------------------------------------------------- 1 | use super::Layer; 2 | use core::fmt; 3 | 4 | /// Two middlewares chained together. 5 | #[derive(Clone)] 6 | pub struct Stack { 7 | inner: Inner, 8 | outer: Outer, 9 | } 10 | 11 | impl Stack { 12 | /// Create a new `Stack`. 13 | pub const fn new(inner: Inner, outer: Outer) -> Self { 14 | Stack { inner, outer } 15 | } 16 | } 17 | 18 | impl Layer for Stack 19 | where 20 | Inner: Layer, 21 | Outer: Layer, 22 | { 23 | type Service = Outer::Service; 24 | 25 | fn layer(&self, service: S) -> Self::Service { 26 | let inner = self.inner.layer(service); 27 | 28 | self.outer.layer(inner) 29 | } 30 | } 31 | 32 | impl fmt::Debug for Stack 33 | where 34 | Inner: fmt::Debug, 35 | Outer: fmt::Debug, 36 | { 37 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 38 | // The generated output of nested `Stack`s is very noisy and makes 39 | // it harder to understand what is in a `ServiceBuilder`. 40 | // 41 | // Instead, this output is designed assuming that a `Stack` is 42 | // usually quite nested, and inside a `ServiceBuilder`. Therefore, 43 | // this skips using `f.debug_struct()`, since each one would force 44 | // a new layer of indentation. 45 | // 46 | // - In compact mode, a nested stack ends up just looking like a flat 47 | // list of layers. 48 | // 49 | // - In pretty mode, while a newline is inserted between each layer, 50 | // the `DebugStruct` used in the `ServiceBuilder` will inject padding 51 | // to that each line is at the same indentation level. 52 | // 53 | // Also, the order of [outer, inner] is important, since it reflects 54 | // the order that the layers were added to the stack. 55 | if f.alternate() { 56 | // pretty 57 | write!(f, "{:#?},\n{:#?}", self.outer, self.inner) 58 | } else { 59 | write!(f, "{:?}, {:?}", self.outer, self.inner) 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /tower-service/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.3.2 2 | 3 | - **all**: new functions const when possible ([#760]) 4 | - **documentation**: Clarify subtlety around cloning and readiness in the `Service` docs. ([#622]) 5 | - **documentation**: service: Call inner.poll_ready() in docs when cloning inner ([#679]) 6 | 7 | [#760]: https://github.com/tower-rs/tower/pull/760 8 | [#622]: https://github.com/tower-rs/tower/pull/662 9 | [#679]: https://github.com/tower-rs/tower/pull/679 10 | 11 | # 0.3.1 (November 29, 2019) 12 | 13 | - Improve example in `Service` docs. ([#510]) 14 | 15 | [#510]: https://github.com/tower-rs/tower/pull/510 16 | 17 | # 0.3.0 (November 29, 2019) 18 | 19 | - Update to `futures 0.3`. 20 | - Update documentation for `std::future::Future`. 21 | 22 | # 0.3.0-alpha.2 (September 30, 2019) 23 | 24 | - Documentation fixes. 25 | 26 | # 0.3.0-alpha.1 (Aug 20, 2019) 27 | 28 | * Switch to `std::future::Future` 29 | 30 | # 0.2.0 (Dec 12, 2018) 31 | 32 | * Change `Service`'s `Request` associated type to be a generic instead. 33 | * Before: 34 | 35 | ```rust 36 | impl Service for Client { 37 | type Request = HttpRequest; 38 | type Response = HttpResponse; 39 | // ... 40 | } 41 | ``` 42 | * After: 43 | 44 | ```rust 45 | impl Service for Client { 46 | type Response = HttpResponse; 47 | // ... 48 | } 49 | ``` 50 | * Remove `NewService`, use `tower_util::MakeService` instead. 51 | * Remove `Service::ready` and `Ready`, use `tower_util::ServiceExt` instead. 52 | 53 | # 0.1.0 (Aug 9, 2018) 54 | 55 | * Initial release 56 | -------------------------------------------------------------------------------- /tower-service/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tower-service" 3 | # When releasing to crates.io: 4 | # - Update doc url 5 | # - Cargo.toml 6 | # - README.md 7 | # - Update CHANGELOG.md. 8 | # - Create "v0.2.x" git tag. 9 | version = "0.3.3" 10 | authors = ["Tower Maintainers "] 11 | license = "MIT" 12 | readme = "README.md" 13 | repository = "https://github.com/tower-rs/tower" 14 | homepage = "https://github.com/tower-rs/tower" 15 | documentation = "https://docs.rs/tower-service/0.3.3" 16 | description = """ 17 | Trait representing an asynchronous, request / response based, client or server. 18 | """ 19 | categories = ["asynchronous", "network-programming"] 20 | edition = "2018" 21 | 22 | [dependencies] 23 | 24 | [dev-dependencies] 25 | http = { workspace = true } 26 | tower-layer = { version = "0.3", path = "../tower-layer" } 27 | tokio = { workspace = true, features = ["macros", "time"] } 28 | futures = { workspace = true } 29 | -------------------------------------------------------------------------------- /tower-service/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Tower Contributors 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /tower-service/README.md: -------------------------------------------------------------------------------- 1 | # Tower Service 2 | 3 | The foundational `Service` trait that [Tower] is based on. 4 | 5 | [![Crates.io][crates-badge]][crates-url] 6 | [![Documentation][docs-badge]][docs-url] 7 | [![Documentation (master)][docs-master-badge]][docs-master-url] 8 | [![MIT licensed][mit-badge]][mit-url] 9 | [![Build Status][actions-badge]][actions-url] 10 | [![Discord chat][discord-badge]][discord-url] 11 | 12 | [crates-badge]: https://img.shields.io/crates/v/tower-service.svg 13 | [crates-url]: https://crates.io/crates/tower-service 14 | [docs-badge]: https://docs.rs/tower-service/badge.svg 15 | [docs-url]: https://docs.rs/tower-service 16 | [docs-master-badge]: https://img.shields.io/badge/docs-master-blue 17 | [docs-master-url]: https://tower-rs.github.io/tower/tower_service 18 | [mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg 19 | [mit-url]: LICENSE 20 | [actions-badge]: https://github.com/tower-rs/tower/workflows/CI/badge.svg 21 | [actions-url]:https://github.com/tower-rs/tower/actions?query=workflow%3ACI 22 | [discord-badge]: https://img.shields.io/discord/500028886025895936?logo=discord&label=discord&logoColor=white 23 | [discord-url]: https://discord.gg/EeF3cQw 24 | 25 | ## Overview 26 | 27 | The [`Service`] trait provides the foundation upon which [Tower] is built. It is a 28 | simple, but powerful trait. At its heart, `Service` is just an asynchronous 29 | function of request to response. 30 | 31 | ``` 32 | async fn(Request) -> Result 33 | ``` 34 | 35 | Implementations of `Service` take a request, the type of which varies per 36 | protocol, and returns a future representing the eventual completion or failure 37 | of the response. 38 | 39 | Services are used to represent both clients and servers. An *instance* of 40 | `Service` is used through a client; a server *implements* `Service`. 41 | 42 | By using standardizing the interface, middleware can be created. Middleware 43 | *implement* `Service` by passing the request to another `Service`. The 44 | middleware may take actions such as modify the request. 45 | 46 | [`Service`]: https://docs.rs/tower-service/latest/tower_service/trait.Service.html 47 | [Tower]: https://crates.io/crates/tower 48 | 49 | ## `no_std` 50 | 51 | `tower-service` is `no_std` compatible, but it (currently) requires the `alloc` crate. 52 | 53 | ## License 54 | 55 | This project is licensed under the [MIT license](LICENSE). 56 | 57 | ### Contribution 58 | 59 | Unless you explicitly state otherwise, any contribution intentionally submitted 60 | for inclusion in Tower by you, shall be licensed as MIT, without any additional 61 | terms or conditions. 62 | -------------------------------------------------------------------------------- /tower-test/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.5.0 (August 1, 2023) 2 | 3 | - Update dependency on tower to 0.5.0-alpha.1. 4 | 5 | # 0.4.0 (January 7, 2021) 6 | 7 | - Updated `tokio-test` dependency to 0.4 8 | - Updated `tokio` dependency to 1.0 9 | 10 | # 0.3.0 (December 19, 2019) 11 | 12 | - Remove `futures-executor` dependency 13 | - Update to non-alpha versions 14 | - Add `mock::task_fn` util fn 15 | 16 | # 0.3.0-alpha.2 (September 30, 2019) 17 | 18 | - Move to `futures-*-preview 0.3.0-alpha.19` 19 | - Move to `pin-project 0.4` 20 | 21 | # 0.3.0-alpha.1 (September 11, 2019) 22 | 23 | - Move to `std::future` 24 | 25 | # 0.1.0 (April 26, 2019) 26 | 27 | - Initial release 28 | -------------------------------------------------------------------------------- /tower-test/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tower-test" 3 | # When releasing to crates.io: 4 | # - Update doc url 5 | # - Cargo.toml 6 | # - README.md 7 | # - Update CHANGELOG.md. 8 | # - Create "v0.1.x" git tag. 9 | version = "0.4.1" 10 | authors = ["Tower Maintainers "] 11 | license = "MIT" 12 | readme = "README.md" 13 | repository = "https://github.com/tower-rs/tower" 14 | homepage = "https://github.com/tower-rs/tower" 15 | documentation = "https://docs.rs/tower-test/0.4.0" 16 | description = """ 17 | Utilities for writing client and server `Service` tests. 18 | """ 19 | categories = ["asynchronous", "network-programming"] 20 | edition = "2018" 21 | 22 | [dependencies] 23 | tokio = { workspace = true, features = ["sync"] } 24 | tokio-test = { workspace = true } 25 | tower-layer = { version = "0.3", path = "../tower-layer" } 26 | tower-service = { version = "0.3", path = "../tower-service" } 27 | pin-project-lite = { workspace = true } 28 | 29 | [dev-dependencies] 30 | tokio = { workspace = true, features = ["macros"] } 31 | -------------------------------------------------------------------------------- /tower-test/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Tower Contributors 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /tower-test/README.md: -------------------------------------------------------------------------------- 1 | # Tower Test 2 | 3 | Utilities for writing client and server `Service` tests. 4 | 5 | [![Crates.io][crates-badge]][crates-url] 6 | [![Documentation][docs-badge]][docs-url] 7 | [![Documentation (master)][docs-master-badge]][docs-master-url] 8 | [![MIT licensed][mit-badge]][mit-url] 9 | [![Build Status][actions-badge]][actions-url] 10 | [![Discord chat][discord-badge]][discord-url] 11 | 12 | [crates-badge]: https://img.shields.io/crates/v/tower-test.svg 13 | [crates-url]: https://crates.io/crates/tower-test 14 | [docs-badge]: https://docs.rs/tower-test/badge.svg 15 | [docs-url]: https://docs.rs/tower-test 16 | [docs-master-badge]: https://img.shields.io/badge/docs-master-blue 17 | [docs-master-url]: https://tower-rs.github.io/tower/tower_test 18 | [mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg 19 | [mit-url]: LICENSE 20 | [actions-badge]: https://github.com/tower-rs/tower/workflows/CI/badge.svg 21 | [actions-url]:https://github.com/tower-rs/tower/actions?query=workflow%3ACI 22 | [discord-badge]: https://img.shields.io/discord/500028886025895936?logo=discord&label=discord&logoColor=white 23 | [discord-url]: https://discord.gg/EeF3cQw 24 | 25 | ## License 26 | 27 | This project is licensed under the [MIT license](LICENSE). 28 | 29 | ### Contribution 30 | 31 | Unless you explicitly state otherwise, any contribution intentionally submitted 32 | for inclusion in Tower by you, shall be licensed as MIT, without any additional 33 | terms or conditions. 34 | -------------------------------------------------------------------------------- /tower-test/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![warn( 2 | missing_debug_implementations, 3 | missing_docs, 4 | rust_2018_idioms, 5 | unreachable_pub 6 | )] 7 | #![forbid(unsafe_code)] 8 | #![allow(elided_lifetimes_in_paths)] 9 | // `rustdoc::broken_intra_doc_links` is checked on CI 10 | 11 | //! Mock `Service` that can be used in tests. 12 | 13 | mod macros; 14 | pub mod mock; 15 | -------------------------------------------------------------------------------- /tower-test/src/macros.rs: -------------------------------------------------------------------------------- 1 | /// Asserts that the mock handle receives a new request equal to the given 2 | /// value. 3 | /// 4 | /// On success, the [`SendResponse`] handle for the matched request is returned, 5 | /// allowing the caller to respond to the request. On failure, the macro panics. 6 | /// 7 | /// # Examples 8 | /// 9 | /// ```rust 10 | /// use tower_service::Service; 11 | /// use tower_test::{mock, assert_request_eq}; 12 | /// use tokio_test::assert_ready; 13 | /// 14 | /// # async fn test() { 15 | /// let (mut service, mut handle) = mock::spawn(); 16 | /// 17 | /// assert_ready!(service.poll_ready()); 18 | /// 19 | /// let response = service.call("hello"); 20 | /// 21 | /// assert_request_eq!(handle, "hello").send_response("world"); 22 | /// 23 | /// assert_eq!(response.await.unwrap(), "world"); 24 | /// # } 25 | /// ``` 26 | /// [`SendResponse`]: crate::mock::SendResponse 27 | #[macro_export] 28 | macro_rules! assert_request_eq { 29 | ($mock_handle:expr, $expect:expr) => { 30 | assert_request_eq!($mock_handle, $expect,) 31 | }; 32 | ($mock_handle:expr, $expect:expr, $($arg:tt)*) => {{ 33 | let (actual, send_response) = match $mock_handle.next_request().await { 34 | Some(r) => r, 35 | None => panic!("expected a request but none was received."), 36 | }; 37 | // In some cases, this may be used with `bool` as the `Request` type, in 38 | // which case, clippy emits a warning. However, this can't be changed to 39 | // `assert!`, because the request type may *not* be `bool`... 40 | #[allow(clippy::bool_assert_comparison)] 41 | { 42 | assert_eq!(actual, $expect, $($arg)*); 43 | } 44 | send_response 45 | }}; 46 | } 47 | -------------------------------------------------------------------------------- /tower-test/src/mock/error.rs: -------------------------------------------------------------------------------- 1 | //! Error types 2 | 3 | use std::{error, fmt}; 4 | 5 | pub(crate) type Error = Box; 6 | 7 | /// Error yielded when a mocked service does not yet accept requests. 8 | #[derive(Debug)] 9 | pub struct Closed(()); 10 | 11 | impl Closed { 12 | pub(crate) fn new() -> Closed { 13 | Closed(()) 14 | } 15 | } 16 | 17 | impl fmt::Display for Closed { 18 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 19 | write!(fmt, "service closed") 20 | } 21 | } 22 | 23 | impl error::Error for Closed {} 24 | -------------------------------------------------------------------------------- /tower-test/src/mock/future.rs: -------------------------------------------------------------------------------- 1 | //! Future types 2 | 3 | use crate::mock::error::{self, Error}; 4 | use pin_project_lite::pin_project; 5 | use tokio::sync::oneshot; 6 | 7 | use std::{ 8 | future::Future, 9 | pin::Pin, 10 | task::{ready, Context, Poll}, 11 | }; 12 | 13 | pin_project! { 14 | /// Future of the `Mock` response. 15 | #[derive(Debug)] 16 | pub struct ResponseFuture { 17 | #[pin] 18 | rx: Option>, 19 | } 20 | } 21 | 22 | type Rx = oneshot::Receiver>; 23 | 24 | impl ResponseFuture { 25 | pub(crate) fn new(rx: Rx) -> ResponseFuture { 26 | ResponseFuture { rx: Some(rx) } 27 | } 28 | 29 | pub(crate) fn closed() -> ResponseFuture { 30 | ResponseFuture { rx: None } 31 | } 32 | } 33 | 34 | impl Future for ResponseFuture { 35 | type Output = Result; 36 | 37 | fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { 38 | match self.project().rx.as_pin_mut() { 39 | Some(rx) => match ready!(rx.poll(cx)) { 40 | Ok(r) => Poll::Ready(r), 41 | Err(_) => Poll::Ready(Err(error::Closed::new().into())), 42 | }, 43 | None => Poll::Ready(Err(error::Closed::new().into())), 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /tower-test/src/mock/spawn.rs: -------------------------------------------------------------------------------- 1 | //! Spawn mock services onto a mock task. 2 | 3 | use std::task::Poll; 4 | use tokio_test::task; 5 | use tower_service::Service; 6 | 7 | /// Service spawned on a mock task 8 | #[derive(Debug)] 9 | pub struct Spawn { 10 | inner: T, 11 | task: task::Spawn<()>, 12 | } 13 | 14 | impl Spawn { 15 | /// Create a new spawn. 16 | pub fn new(inner: T) -> Self { 17 | Self { 18 | inner, 19 | task: task::spawn(()), 20 | } 21 | } 22 | 23 | /// Check if this service has been woken up. 24 | pub fn is_woken(&self) -> bool { 25 | self.task.is_woken() 26 | } 27 | 28 | /// Get how many futurs are holding onto the waker. 29 | pub fn waker_ref_count(&self) -> usize { 30 | self.task.waker_ref_count() 31 | } 32 | 33 | /// Poll this service ready. 34 | pub fn poll_ready(&mut self) -> Poll> 35 | where 36 | T: Service, 37 | { 38 | let task = &mut self.task; 39 | let inner = &mut self.inner; 40 | 41 | task.enter(|cx, _| inner.poll_ready(cx)) 42 | } 43 | 44 | /// Call the inner Service. 45 | pub fn call(&mut self, req: Request) -> T::Future 46 | where 47 | T: Service, 48 | { 49 | self.inner.call(req) 50 | } 51 | 52 | /// Get the inner service. 53 | pub fn into_inner(self) -> T { 54 | self.inner 55 | } 56 | 57 | /// Get a reference to the inner service. 58 | pub fn get_ref(&self) -> &T { 59 | &self.inner 60 | } 61 | 62 | /// Get a mutable reference to the inner service. 63 | pub fn get_mut(&mut self) -> &mut T { 64 | &mut self.inner 65 | } 66 | } 67 | 68 | impl Clone for Spawn { 69 | fn clone(&self) -> Self { 70 | Spawn::new(self.inner.clone()) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /tower-test/tests/mock.rs: -------------------------------------------------------------------------------- 1 | use tokio_test::{assert_pending, assert_ready}; 2 | use tower_test::{assert_request_eq, mock}; 3 | 4 | #[tokio::test(flavor = "current_thread")] 5 | async fn single_request_ready() { 6 | let (mut service, mut handle) = mock::spawn(); 7 | 8 | assert_pending!(handle.poll_request()); 9 | 10 | assert_ready!(service.poll_ready()).unwrap(); 11 | 12 | let response = service.call("hello"); 13 | 14 | assert_request_eq!(handle, "hello").send_response("world"); 15 | 16 | assert_eq!(response.await.unwrap(), "world"); 17 | } 18 | 19 | #[tokio::test(flavor = "current_thread")] 20 | #[should_panic] 21 | async fn backpressure() { 22 | let (mut service, mut handle) = mock::spawn::<_, ()>(); 23 | 24 | handle.allow(0); 25 | 26 | assert_pending!(service.poll_ready()); 27 | 28 | service.call("hello").await.unwrap(); 29 | } 30 | -------------------------------------------------------------------------------- /tower/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tower" 3 | # When releasing to crates.io: 4 | # - Update README.md 5 | # - Update CHANGELOG.md. 6 | # - Create "vX.X.X" git tag. 7 | version = "0.5.2" 8 | authors = ["Tower Maintainers "] 9 | license = "MIT" 10 | readme = "README.md" 11 | repository = "https://github.com/tower-rs/tower" 12 | homepage = "https://github.com/tower-rs/tower" 13 | description = """ 14 | Tower is a library of modular and reusable components for building robust 15 | clients and servers. 16 | """ 17 | categories = ["asynchronous", "network-programming"] 18 | keywords = ["io", "async", "non-blocking", "futures", "service"] 19 | edition = "2018" 20 | rust-version = "1.64.0" 21 | 22 | [features] 23 | full = [ 24 | "balance", 25 | "buffer", 26 | "discover", 27 | "filter", 28 | "hedge", 29 | "limit", 30 | "load", 31 | "load-shed", 32 | "make", 33 | "ready-cache", 34 | "reconnect", 35 | "retry", 36 | "spawn-ready", 37 | "steer", 38 | "timeout", 39 | "util", 40 | ] 41 | # FIXME: Use weak dependency once available (https://github.com/rust-lang/cargo/issues/8832) 42 | log = ["tracing/log"] 43 | balance = ["discover", "load", "ready-cache", "make", "slab", "util"] 44 | buffer = ["tokio/sync", "tokio/rt", "tokio-util", "tracing", "pin-project-lite"] 45 | discover = ["futures-core", "pin-project-lite"] 46 | filter = ["futures-util", "pin-project-lite"] 47 | hedge = ["util", "filter", "futures-util", "hdrhistogram", "tokio/time", "tracing"] 48 | limit = ["tokio/time", "tokio/sync", "tokio-util", "tracing", "pin-project-lite"] 49 | load = ["tokio/time", "tracing", "pin-project-lite"] 50 | load-shed = ["pin-project-lite"] 51 | make = ["pin-project-lite", "tokio/io-std"] 52 | ready-cache = ["futures-core", "futures-util", "indexmap", "tokio/sync", "tracing", "pin-project-lite"] 53 | reconnect = ["make", "tokio/io-std", "tracing"] 54 | retry = ["tokio/time", "util"] 55 | spawn-ready = ["futures-util", "tokio/sync", "tokio/rt", "util", "tracing"] 56 | steer = [] 57 | timeout = ["pin-project-lite", "tokio/time"] 58 | util = ["futures-core", "futures-util", "pin-project-lite", "sync_wrapper"] 59 | 60 | [dependencies] 61 | tower-layer = { version = "0.3.3", path = "../tower-layer" } 62 | tower-service = { version = "0.3.3", path = "../tower-service" } 63 | 64 | futures-core = { workspace = true, optional = true } 65 | futures-util = { workspace = true, features = ["alloc"], optional = true } 66 | hdrhistogram = { workspace = true, optional = true } 67 | indexmap = { workspace = true, optional = true } 68 | slab = { workspace = true, optional = true } 69 | tokio = { workspace = true, features = ["sync"], optional = true } 70 | tokio-stream = { workspace = true, optional = true } 71 | tokio-util = { workspace = true, optional = true } 72 | tracing = { workspace = true, features = ["std"], optional = true } 73 | pin-project-lite = { workspace = true, optional = true } 74 | sync_wrapper = { workspace = true, optional = true } 75 | 76 | [dev-dependencies] 77 | futures = { workspace = true } 78 | hdrhistogram = { workspace = true } 79 | pin-project-lite = { workspace = true } 80 | tokio = { workspace = true, features = ["macros", "sync", "test-util", "rt-multi-thread"] } 81 | tokio-stream = { workspace = true } 82 | tokio-test = { workspace = true } 83 | tower-test = { version = "0.4", path = "../tower-test" } 84 | tracing = { workspace = true, features = ["std"] } 85 | tracing-subscriber = { workspace = true, features = ["fmt", "ansi"] } 86 | http = { workspace = true } 87 | lazy_static = { workspace = true } 88 | rand = { workspace = true, features = ["small_rng"] } 89 | quickcheck = { workspace = true } 90 | 91 | [package.metadata.docs.rs] 92 | all-features = true 93 | rustdoc-args = ["--cfg", "docsrs"] 94 | 95 | [package.metadata.playground] 96 | features = ["full"] 97 | 98 | [[example]] 99 | name = "tower-balance" 100 | path = "examples/tower-balance.rs" 101 | required-features = ["full"] 102 | -------------------------------------------------------------------------------- /tower/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Tower Contributors 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /tower/src/balance/error.rs: -------------------------------------------------------------------------------- 1 | //! Error types for the [`tower::balance`] middleware. 2 | //! 3 | //! [`tower::balance`]: crate::balance 4 | 5 | use std::fmt; 6 | 7 | /// The balancer's endpoint discovery stream failed. 8 | #[derive(Debug)] 9 | pub struct Discover(pub(crate) crate::BoxError); 10 | 11 | impl fmt::Display for Discover { 12 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 13 | write!(f, "load balancer discovery error: {}", self.0) 14 | } 15 | } 16 | 17 | impl std::error::Error for Discover { 18 | fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { 19 | Some(&*self.0) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tower/src/balance/mod.rs: -------------------------------------------------------------------------------- 1 | //! Middleware that allows balancing load among multiple services. 2 | //! 3 | //! In larger systems, multiple endpoints are often available for a given service. As load 4 | //! increases, you want to ensure that that load is spread evenly across the available services. 5 | //! Otherwise, clients could see spikes in latency if their request goes to a particularly loaded 6 | //! service, even when spare capacity is available to handle that request elsewhere. 7 | //! 8 | //! This module provides the [`p2c`] middleware, which implements the "[Power of 9 | //! Two Random Choices]" algorithm. This is a simple but robust technique for 10 | //! spreading load across services with only inexact load measurements. Use this 11 | //! if the set of available services is not within your control, and you simply 12 | //! want to spread load among that set of services. 13 | //! 14 | //! [Power of Two Random Choices]: http://www.eecs.harvard.edu/~michaelm/postscripts/handbook2001.pdf 15 | //! 16 | //! # Examples 17 | //! 18 | //! ```rust 19 | //! # #[cfg(feature = "util")] 20 | //! # #[cfg(feature = "load")] 21 | //! # fn warnings_are_errors() { 22 | //! use tower::balance::p2c::Balance; 23 | //! use tower::load::Load; 24 | //! use tower::{Service, ServiceExt}; 25 | //! use futures_util::pin_mut; 26 | //! # use futures_core::Stream; 27 | //! # use futures_util::StreamExt; 28 | //! 29 | //! async fn spread + Load>(svc1: S, svc2: S, reqs: impl Stream) 30 | //! where 31 | //! S::Error: Into, 32 | //! # // this bound is pretty unfortunate, and the compiler does _not_ help 33 | //! S::Metric: std::fmt::Debug, 34 | //! { 35 | //! // Spread load evenly across the two services 36 | //! let p2c = Balance::new(tower::discover::ServiceList::new(vec![svc1, svc2])); 37 | //! 38 | //! // Issue all the requests that come in. 39 | //! // Some will go to svc1, some will go to svc2. 40 | //! pin_mut!(reqs); 41 | //! let mut responses = p2c.call_all(reqs); 42 | //! while let Some(rsp) = responses.next().await { 43 | //! // ... 44 | //! } 45 | //! } 46 | //! # } 47 | //! ``` 48 | 49 | pub mod error; 50 | pub mod p2c; 51 | -------------------------------------------------------------------------------- /tower/src/balance/p2c/layer.rs: -------------------------------------------------------------------------------- 1 | use super::MakeBalance; 2 | use std::{fmt, marker::PhantomData}; 3 | use tower_layer::Layer; 4 | 5 | /// Construct load balancers ([`Balance`]) over dynamic service sets ([`Discover`]) produced by the 6 | /// "inner" service in response to requests coming from the "outer" service. 7 | /// 8 | /// This construction may seem a little odd at first glance. This is not a layer that takes 9 | /// requests and produces responses in the traditional sense. Instead, it is more like 10 | /// [`MakeService`] in that it takes service _descriptors_ (see `Target` on [`MakeService`]) 11 | /// and produces _services_. Since [`Balance`] spreads requests across a _set_ of services, 12 | /// the inner service should produce a [`Discover`], not just a single 13 | /// [`Service`], given a service descriptor. 14 | /// 15 | /// See the [module-level documentation](crate::balance) for details on load balancing. 16 | /// 17 | /// [`Balance`]: crate::balance::p2c::Balance 18 | /// [`Discover`]: crate::discover::Discover 19 | /// [`MakeService`]: crate::MakeService 20 | /// [`Service`]: crate::Service 21 | pub struct MakeBalanceLayer { 22 | _marker: PhantomData, 23 | } 24 | 25 | impl MakeBalanceLayer { 26 | /// Build balancers using operating system entropy. 27 | pub const fn new() -> Self { 28 | Self { 29 | _marker: PhantomData, 30 | } 31 | } 32 | } 33 | 34 | impl Default for MakeBalanceLayer { 35 | fn default() -> Self { 36 | Self::new() 37 | } 38 | } 39 | 40 | impl Clone for MakeBalanceLayer { 41 | fn clone(&self) -> Self { 42 | Self { 43 | _marker: PhantomData, 44 | } 45 | } 46 | } 47 | 48 | impl Layer for MakeBalanceLayer { 49 | type Service = MakeBalance; 50 | 51 | fn layer(&self, make_discover: S) -> Self::Service { 52 | MakeBalance::new(make_discover) 53 | } 54 | } 55 | 56 | impl fmt::Debug for MakeBalanceLayer { 57 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 58 | f.debug_struct("MakeBalanceLayer").finish() 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /tower/src/balance/p2c/mod.rs: -------------------------------------------------------------------------------- 1 | //! This module implements the "[Power of Two Random Choices]" load balancing algorithm. 2 | //! 3 | //! It is a simple but robust technique for spreading load across services with only inexact load 4 | //! measurements. As its name implies, whenever a request comes in, it samples two ready services 5 | //! at random, and issues the request to whichever service is less loaded. How loaded a service is 6 | //! is determined by the return value of [`Load`](crate::load::Load). 7 | //! 8 | //! As described in the [Finagle Guide][finagle]: 9 | //! 10 | //! > The algorithm randomly picks two services from the set of ready endpoints and 11 | //! > selects the least loaded of the two. By repeatedly using this strategy, we can 12 | //! > expect a manageable upper bound on the maximum load of any server. 13 | //! > 14 | //! > The maximum load variance between any two servers is bound by `ln(ln(n))` where 15 | //! > `n` is the number of servers in the cluster. 16 | //! 17 | //! The balance service and layer implementations rely on _service discovery_ to provide the 18 | //! underlying set of services to balance requests across. This happens through the 19 | //! [`Discover`](crate::discover::Discover) trait, which is essentially a [`Stream`] that indicates 20 | //! when services become available or go away. If you have a fixed set of services, consider using 21 | //! [`ServiceList`](crate::discover::ServiceList). 22 | //! 23 | //! Since the load balancer needs to perform _random_ choices, the constructors in this module 24 | //! usually come in two forms: one that uses randomness provided by the operating system, and one 25 | //! that lets you specify the random seed to use. Usually the former is what you'll want, though 26 | //! the latter may come in handy for reproducibility or to reduce reliance on the operating system. 27 | //! 28 | //! [Power of Two Random Choices]: http://www.eecs.harvard.edu/~michaelm/postscripts/handbook2001.pdf 29 | //! [finagle]: https://twitter.github.io/finagle/guide/Clients.html#power-of-two-choices-p2c-least-loaded 30 | //! [`Stream`]: https://docs.rs/futures/0.3/futures/stream/trait.Stream.html 31 | 32 | mod layer; 33 | mod make; 34 | mod service; 35 | 36 | #[cfg(test)] 37 | mod test; 38 | 39 | pub use layer::MakeBalanceLayer; 40 | pub use make::{MakeBalance, MakeFuture}; 41 | pub use service::Balance; 42 | -------------------------------------------------------------------------------- /tower/src/buffer/error.rs: -------------------------------------------------------------------------------- 1 | //! Error types for the `Buffer` middleware. 2 | 3 | use crate::BoxError; 4 | use std::{fmt, sync::Arc}; 5 | 6 | /// An error produced by a [`Service`] wrapped by a [`Buffer`] 7 | /// 8 | /// [`Service`]: crate::Service 9 | /// [`Buffer`]: crate::buffer::Buffer 10 | #[derive(Debug)] 11 | pub struct ServiceError { 12 | inner: Arc, 13 | } 14 | 15 | /// An error produced when the a buffer's worker closes unexpectedly. 16 | pub struct Closed { 17 | _p: (), 18 | } 19 | 20 | // ===== impl ServiceError ===== 21 | 22 | impl ServiceError { 23 | pub(crate) fn new(inner: BoxError) -> ServiceError { 24 | let inner = Arc::new(inner); 25 | ServiceError { inner } 26 | } 27 | 28 | // Private to avoid exposing `Clone` trait as part of the public API 29 | pub(crate) fn clone(&self) -> ServiceError { 30 | ServiceError { 31 | inner: self.inner.clone(), 32 | } 33 | } 34 | } 35 | 36 | impl fmt::Display for ServiceError { 37 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 38 | write!(fmt, "buffered service failed: {}", self.inner) 39 | } 40 | } 41 | 42 | impl std::error::Error for ServiceError { 43 | fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { 44 | Some(&**self.inner) 45 | } 46 | } 47 | 48 | // ===== impl Closed ===== 49 | 50 | impl Closed { 51 | pub(crate) fn new() -> Self { 52 | Closed { _p: () } 53 | } 54 | } 55 | 56 | impl fmt::Debug for Closed { 57 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 58 | fmt.debug_tuple("Closed").finish() 59 | } 60 | } 61 | 62 | impl fmt::Display for Closed { 63 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 64 | fmt.write_str("buffer's worker closed unexpectedly") 65 | } 66 | } 67 | 68 | impl std::error::Error for Closed {} 69 | -------------------------------------------------------------------------------- /tower/src/buffer/future.rs: -------------------------------------------------------------------------------- 1 | //! Future types for the [`Buffer`] middleware. 2 | //! 3 | //! [`Buffer`]: crate::buffer::Buffer 4 | 5 | use super::{error::Closed, message}; 6 | use pin_project_lite::pin_project; 7 | use std::{ 8 | future::Future, 9 | pin::Pin, 10 | task::{ready, Context, Poll}, 11 | }; 12 | 13 | pin_project! { 14 | /// Future that completes when the buffered service eventually services the submitted request. 15 | #[derive(Debug)] 16 | pub struct ResponseFuture { 17 | #[pin] 18 | state: ResponseState, 19 | } 20 | } 21 | 22 | pin_project! { 23 | #[project = ResponseStateProj] 24 | #[derive(Debug)] 25 | enum ResponseState { 26 | Failed { 27 | error: Option, 28 | }, 29 | Rx { 30 | #[pin] 31 | rx: message::Rx, 32 | }, 33 | Poll { 34 | #[pin] 35 | fut: T, 36 | }, 37 | } 38 | } 39 | 40 | impl ResponseFuture { 41 | pub(crate) fn new(rx: message::Rx) -> Self { 42 | ResponseFuture { 43 | state: ResponseState::Rx { rx }, 44 | } 45 | } 46 | 47 | pub(crate) fn failed(err: crate::BoxError) -> Self { 48 | ResponseFuture { 49 | state: ResponseState::Failed { error: Some(err) }, 50 | } 51 | } 52 | } 53 | 54 | impl Future for ResponseFuture 55 | where 56 | F: Future>, 57 | E: Into, 58 | { 59 | type Output = Result; 60 | 61 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 62 | let mut this = self.project(); 63 | 64 | loop { 65 | match this.state.as_mut().project() { 66 | ResponseStateProj::Failed { error } => { 67 | return Poll::Ready(Err(error.take().expect("polled after error"))); 68 | } 69 | ResponseStateProj::Rx { rx } => match ready!(rx.poll(cx)) { 70 | Ok(Ok(fut)) => this.state.set(ResponseState::Poll { fut }), 71 | Ok(Err(e)) => return Poll::Ready(Err(e.into())), 72 | Err(_) => return Poll::Ready(Err(Closed::new().into())), 73 | }, 74 | ResponseStateProj::Poll { fut } => return fut.poll(cx).map_err(Into::into), 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /tower/src/buffer/layer.rs: -------------------------------------------------------------------------------- 1 | use super::service::Buffer; 2 | use std::{fmt, marker::PhantomData}; 3 | use tower_layer::Layer; 4 | use tower_service::Service; 5 | 6 | /// Adds an mpsc buffer in front of an inner service. 7 | /// 8 | /// The default Tokio executor is used to run the given service, 9 | /// which means that this layer can only be used on the Tokio runtime. 10 | /// 11 | /// See the module documentation for more details. 12 | pub struct BufferLayer { 13 | bound: usize, 14 | _p: PhantomData, 15 | } 16 | 17 | impl BufferLayer { 18 | /// Creates a new [`BufferLayer`] with the provided `bound`. 19 | /// 20 | /// `bound` gives the maximal number of requests that can be queued for the service before 21 | /// backpressure is applied to callers. 22 | /// 23 | /// # A note on choosing a `bound` 24 | /// 25 | /// When [`Buffer`]'s implementation of [`poll_ready`] returns [`Poll::Ready`], it reserves a 26 | /// slot in the channel for the forthcoming [`call`]. However, if this call doesn't arrive, 27 | /// this reserved slot may be held up for a long time. As a result, it's advisable to set 28 | /// `bound` to be at least the maximum number of concurrent requests the [`Buffer`] will see. 29 | /// If you do not, all the slots in the buffer may be held up by futures that have just called 30 | /// [`poll_ready`] but will not issue a [`call`], which prevents other senders from issuing new 31 | /// requests. 32 | /// 33 | /// [`Poll::Ready`]: std::task::Poll::Ready 34 | /// [`call`]: crate::Service::call 35 | /// [`poll_ready`]: crate::Service::poll_ready 36 | pub const fn new(bound: usize) -> Self { 37 | BufferLayer { 38 | bound, 39 | _p: PhantomData, 40 | } 41 | } 42 | } 43 | 44 | impl Layer for BufferLayer 45 | where 46 | S: Service + Send + 'static, 47 | S::Future: Send, 48 | S::Error: Into + Send + Sync, 49 | Request: Send + 'static, 50 | { 51 | type Service = Buffer; 52 | 53 | fn layer(&self, service: S) -> Self::Service { 54 | Buffer::new(service, self.bound) 55 | } 56 | } 57 | 58 | impl fmt::Debug for BufferLayer { 59 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 60 | f.debug_struct("BufferLayer") 61 | .field("bound", &self.bound) 62 | .finish() 63 | } 64 | } 65 | 66 | impl Clone for BufferLayer { 67 | fn clone(&self) -> Self { 68 | Self { 69 | bound: self.bound, 70 | _p: PhantomData, 71 | } 72 | } 73 | } 74 | 75 | impl Copy for BufferLayer {} 76 | -------------------------------------------------------------------------------- /tower/src/buffer/message.rs: -------------------------------------------------------------------------------- 1 | use super::error::ServiceError; 2 | use tokio::sync::oneshot; 3 | 4 | /// Message sent over buffer 5 | #[derive(Debug)] 6 | pub(crate) struct Message { 7 | pub(crate) request: Request, 8 | pub(crate) tx: Tx, 9 | pub(crate) span: tracing::Span, 10 | } 11 | 12 | /// Response sender 13 | pub(crate) type Tx = oneshot::Sender>; 14 | 15 | /// Response receiver 16 | pub(crate) type Rx = oneshot::Receiver>; 17 | -------------------------------------------------------------------------------- /tower/src/buffer/mod.rs: -------------------------------------------------------------------------------- 1 | //! Middleware that provides a buffered mpsc channel to a service. 2 | //! 3 | //! Sometimes you want to give out multiple handles to a single service, and allow each handle to 4 | //! enqueue requests. That is, you want a [`Service`] to be [`Clone`]. This module allows you to do 5 | //! that by placing the service behind a multi-producer, single-consumer buffering channel. Clients 6 | //! enqueue requests by sending on the channel from any of the handles ([`Buffer`]), and the single 7 | //! service running elsewhere (usually spawned) receives and services the requests one by one. Each 8 | //! request is enqueued alongside a response channel that allows the service to report the result 9 | //! of the request back to the caller. 10 | //! 11 | //! # Examples 12 | //! 13 | //! ```rust 14 | //! # #[cfg(feature = "util")] 15 | //! use tower::buffer::Buffer; 16 | //! # #[cfg(feature = "util")] 17 | //! use tower::{Service, ServiceExt}; 18 | //! # #[cfg(feature = "util")] 19 | //! async fn mass_produce>(svc: S) 20 | //! where 21 | //! S: 'static + Send, 22 | //! S::Error: Send + Sync + std::error::Error, 23 | //! S::Future: Send 24 | //! { 25 | //! let svc = Buffer::new(svc, 10 /* buffer length */); 26 | //! for _ in 0..10 { 27 | //! let mut svc = svc.clone(); 28 | //! tokio::spawn(async move { 29 | //! for i in 0usize.. { 30 | //! svc.ready().await.expect("service crashed").call(i).await; 31 | //! } 32 | //! }); 33 | //! } 34 | //! } 35 | //! ``` 36 | //! 37 | //! [`Service`]: crate::Service 38 | 39 | pub mod error; 40 | pub mod future; 41 | mod layer; 42 | mod message; 43 | mod service; 44 | mod worker; 45 | 46 | pub use self::layer::BufferLayer; 47 | pub use self::service::Buffer; 48 | -------------------------------------------------------------------------------- /tower/src/discover/list.rs: -------------------------------------------------------------------------------- 1 | use super::Change; 2 | use futures_core::Stream; 3 | use pin_project_lite::pin_project; 4 | use std::convert::Infallible; 5 | use std::iter::{Enumerate, IntoIterator}; 6 | use std::{ 7 | pin::Pin, 8 | task::{Context, Poll}, 9 | }; 10 | use tower_service::Service; 11 | 12 | pin_project! { 13 | /// Static service discovery based on a predetermined list of services. 14 | /// 15 | /// [`ServiceList`] is created with an initial list of services. The discovery 16 | /// process will yield this list once and do nothing after. 17 | #[derive(Debug)] 18 | pub struct ServiceList 19 | where 20 | T: IntoIterator, 21 | { 22 | inner: Enumerate, 23 | } 24 | } 25 | 26 | impl ServiceList 27 | where 28 | T: IntoIterator, 29 | { 30 | #[allow(missing_docs)] 31 | pub fn new(services: T) -> ServiceList 32 | where 33 | U: Service, 34 | { 35 | ServiceList { 36 | inner: services.into_iter().enumerate(), 37 | } 38 | } 39 | } 40 | 41 | impl Stream for ServiceList 42 | where 43 | T: IntoIterator, 44 | { 45 | type Item = Result, Infallible>; 46 | 47 | fn poll_next(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { 48 | match self.project().inner.next() { 49 | Some((i, service)) => Poll::Ready(Some(Ok(Change::Insert(i, service)))), 50 | None => Poll::Ready(None), 51 | } 52 | } 53 | } 54 | 55 | // check that List can be directly over collections 56 | #[cfg(test)] 57 | #[allow(dead_code)] 58 | type ListVecTest = ServiceList>; 59 | 60 | #[cfg(test)] 61 | #[allow(dead_code)] 62 | type ListVecIterTest = ServiceList<::std::vec::IntoIter>; 63 | -------------------------------------------------------------------------------- /tower/src/discover/mod.rs: -------------------------------------------------------------------------------- 1 | //! Service discovery 2 | //! 3 | //! This module provides the [`Change`] enum, which indicates the arrival or departure of a service 4 | //! from a collection of similar services. Most implementations should use the [`Discover`] trait 5 | //! in their bounds to indicate that they can handle services coming and going. [`Discover`] itself 6 | //! is primarily a convenience wrapper around [`TryStream`][`TryStream`]. 7 | //! 8 | //! Every discovered service is assigned an identifier that is distinct among the currently active 9 | //! services. If that service later goes away, a [`Change::Remove`] is yielded with that service's 10 | //! identifier. From that point forward, the identifier may be re-used. 11 | //! 12 | //! # Examples 13 | //! 14 | //! ```rust 15 | //! use std::future::poll_fn; 16 | //! use futures_util::pin_mut; 17 | //! use tower::discover::{Change, Discover}; 18 | //! async fn services_monitor(services: D) { 19 | //! pin_mut!(services); 20 | //! while let Some(Ok(change)) = poll_fn(|cx| services.as_mut().poll_discover(cx)).await { 21 | //! match change { 22 | //! Change::Insert(key, svc) => { 23 | //! // a new service with identifier `key` was discovered 24 | //! # let _ = (key, svc); 25 | //! } 26 | //! Change::Remove(key) => { 27 | //! // the service with identifier `key` has gone away 28 | //! # let _ = (key); 29 | //! } 30 | //! } 31 | //! } 32 | //! } 33 | //! ``` 34 | //! 35 | //! [`TryStream`]: https://docs.rs/futures/latest/futures/stream/trait.TryStream.html 36 | 37 | mod list; 38 | 39 | pub use self::list::ServiceList; 40 | 41 | use crate::sealed::Sealed; 42 | use futures_core::TryStream; 43 | use std::{ 44 | pin::Pin, 45 | task::{Context, Poll}, 46 | }; 47 | 48 | /// A dynamically changing set of related services. 49 | /// 50 | /// As new services arrive and old services are retired, 51 | /// [`Change`]s are returned which provide unique identifiers 52 | /// for the services. 53 | /// 54 | /// See the module documentation for more details. 55 | pub trait Discover: Sealed> { 56 | /// A unique identifier for each active service. 57 | /// 58 | /// An identifier can be re-used once a [`Change::Remove`] has been yielded for its service. 59 | type Key: Eq; 60 | 61 | /// The type of [`Service`] yielded by this [`Discover`]. 62 | /// 63 | /// [`Service`]: crate::Service 64 | type Service; 65 | 66 | /// Error produced during discovery 67 | type Error; 68 | 69 | /// Yields the next discovery change set. 70 | fn poll_discover( 71 | self: Pin<&mut Self>, 72 | cx: &mut Context<'_>, 73 | ) -> Poll, Self::Error>>>; 74 | } 75 | 76 | impl Sealed> for D 77 | where 78 | D: TryStream, Error = E>, 79 | K: Eq, 80 | { 81 | } 82 | 83 | impl Discover for D 84 | where 85 | D: TryStream, Error = E>, 86 | K: Eq, 87 | { 88 | type Key = K; 89 | type Service = S; 90 | type Error = E; 91 | 92 | fn poll_discover( 93 | self: Pin<&mut Self>, 94 | cx: &mut Context<'_>, 95 | ) -> Poll>> { 96 | TryStream::try_poll_next(self, cx) 97 | } 98 | } 99 | 100 | /// A change in the service set. 101 | #[derive(Debug, Clone)] 102 | pub enum Change { 103 | /// A new service identified by key `K` was identified. 104 | Insert(K, V), 105 | /// The service identified by key `K` disappeared. 106 | Remove(K), 107 | } 108 | -------------------------------------------------------------------------------- /tower/src/filter/future.rs: -------------------------------------------------------------------------------- 1 | //! Future types 2 | 3 | use super::AsyncPredicate; 4 | use crate::BoxError; 5 | use pin_project_lite::pin_project; 6 | use std::{ 7 | future::Future, 8 | pin::Pin, 9 | task::{ready, Context, Poll}, 10 | }; 11 | use tower_service::Service; 12 | 13 | pin_project! { 14 | /// Filtered response future from [`AsyncFilter`] services. 15 | /// 16 | /// [`AsyncFilter`]: crate::filter::AsyncFilter 17 | #[derive(Debug)] 18 | pub struct AsyncResponseFuture 19 | where 20 | P: AsyncPredicate, 21 | S: Service, 22 | { 23 | #[pin] 24 | state: State, 25 | 26 | // Inner service 27 | service: S, 28 | } 29 | } 30 | 31 | opaque_future! { 32 | /// Filtered response future from [`Filter`] services. 33 | /// 34 | /// [`Filter`]: crate::filter::Filter 35 | pub type ResponseFuture = 36 | futures_util::future::Either< 37 | std::future::Ready>, 38 | futures_util::future::ErrInto 39 | >; 40 | } 41 | 42 | pin_project! { 43 | #[project = StateProj] 44 | #[derive(Debug)] 45 | enum State { 46 | /// Waiting for the predicate future 47 | Check { 48 | #[pin] 49 | check: F 50 | }, 51 | /// Waiting for the response future 52 | WaitResponse { 53 | #[pin] 54 | response: G 55 | }, 56 | } 57 | } 58 | 59 | impl AsyncResponseFuture 60 | where 61 | P: AsyncPredicate, 62 | S: Service, 63 | S::Error: Into, 64 | { 65 | pub(crate) fn new(check: P::Future, service: S) -> Self { 66 | Self { 67 | state: State::Check { check }, 68 | service, 69 | } 70 | } 71 | } 72 | 73 | impl Future for AsyncResponseFuture 74 | where 75 | P: AsyncPredicate, 76 | S: Service, 77 | S::Error: Into, 78 | { 79 | type Output = Result; 80 | 81 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 82 | let mut this = self.project(); 83 | 84 | loop { 85 | match this.state.as_mut().project() { 86 | StateProj::Check { mut check } => { 87 | let request = ready!(check.as_mut().poll(cx))?; 88 | let response = this.service.call(request); 89 | this.state.set(State::WaitResponse { response }); 90 | } 91 | StateProj::WaitResponse { response } => { 92 | return response.poll(cx).map_err(Into::into); 93 | } 94 | } 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /tower/src/filter/layer.rs: -------------------------------------------------------------------------------- 1 | use super::{AsyncFilter, Filter}; 2 | use tower_layer::Layer; 3 | 4 | /// Conditionally dispatch requests to the inner service based on a synchronous 5 | /// [predicate]. 6 | /// 7 | /// This [`Layer`] produces instances of the [`Filter`] service. 8 | /// 9 | /// [predicate]: crate::filter::Predicate 10 | /// [`Layer`]: crate::Layer 11 | /// [`Filter`]: crate::filter::Filter 12 | #[derive(Debug, Clone)] 13 | pub struct FilterLayer { 14 | predicate: U, 15 | } 16 | 17 | /// Conditionally dispatch requests to the inner service based on an asynchronous 18 | /// [predicate]. 19 | /// 20 | /// This [`Layer`] produces instances of the [`AsyncFilter`] service. 21 | /// 22 | /// [predicate]: crate::filter::AsyncPredicate 23 | /// [`Layer`]: crate::Layer 24 | /// [`Filter`]: crate::filter::AsyncFilter 25 | #[derive(Debug, Clone)] 26 | pub struct AsyncFilterLayer { 27 | predicate: U, 28 | } 29 | 30 | // === impl FilterLayer === 31 | 32 | impl FilterLayer { 33 | /// Returns a new layer that produces [`Filter`] services with the given 34 | /// [`Predicate`]. 35 | /// 36 | /// [`Predicate`]: crate::filter::Predicate 37 | /// [`Filter`]: crate::filter::Filter 38 | pub const fn new(predicate: U) -> Self { 39 | Self { predicate } 40 | } 41 | } 42 | 43 | impl Layer for FilterLayer { 44 | type Service = Filter; 45 | 46 | fn layer(&self, service: S) -> Self::Service { 47 | let predicate = self.predicate.clone(); 48 | Filter::new(service, predicate) 49 | } 50 | } 51 | 52 | // === impl AsyncFilterLayer === 53 | 54 | impl AsyncFilterLayer { 55 | /// Returns a new layer that produces [`AsyncFilter`] services with the given 56 | /// [`AsyncPredicate`]. 57 | /// 58 | /// [`AsyncPredicate`]: crate::filter::AsyncPredicate 59 | /// [`Filter`]: crate::filter::Filter 60 | pub const fn new(predicate: U) -> Self { 61 | Self { predicate } 62 | } 63 | } 64 | 65 | impl Layer for AsyncFilterLayer { 66 | type Service = AsyncFilter; 67 | 68 | fn layer(&self, service: S) -> Self::Service { 69 | let predicate = self.predicate.clone(); 70 | AsyncFilter::new(service, predicate) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /tower/src/filter/predicate.rs: -------------------------------------------------------------------------------- 1 | use crate::BoxError; 2 | use std::future::Future; 3 | 4 | /// Checks a request asynchronously. 5 | pub trait AsyncPredicate { 6 | /// The future returned by [`check`]. 7 | /// 8 | /// [`check`]: crate::filter::AsyncPredicate::check 9 | type Future: Future>; 10 | 11 | /// The type of requests returned by [`check`]. 12 | /// 13 | /// This request is forwarded to the inner service if the predicate 14 | /// succeeds. 15 | /// 16 | /// [`check`]: crate::filter::AsyncPredicate::check 17 | type Request; 18 | 19 | /// Check whether the given request should be forwarded. 20 | /// 21 | /// If the future resolves with [`Ok`], the request is forwarded to the inner service. 22 | fn check(&mut self, request: Request) -> Self::Future; 23 | } 24 | /// Checks a request synchronously. 25 | pub trait Predicate { 26 | /// The type of requests returned by [`check`]. 27 | /// 28 | /// This request is forwarded to the inner service if the predicate 29 | /// succeeds. 30 | /// 31 | /// [`check`]: crate::filter::Predicate::check 32 | type Request; 33 | 34 | /// Check whether the given request should be forwarded. 35 | /// 36 | /// If the future resolves with [`Ok`], the request is forwarded to the inner service. 37 | fn check(&mut self, request: Request) -> Result; 38 | } 39 | 40 | impl AsyncPredicate for F 41 | where 42 | F: FnMut(T) -> U, 43 | U: Future>, 44 | E: Into, 45 | { 46 | type Future = futures_util::future::ErrInto; 47 | type Request = R; 48 | 49 | fn check(&mut self, request: T) -> Self::Future { 50 | use futures_util::TryFutureExt; 51 | self(request).err_into() 52 | } 53 | } 54 | 55 | impl Predicate for F 56 | where 57 | F: FnMut(T) -> Result, 58 | E: Into, 59 | { 60 | type Request = R; 61 | 62 | fn check(&mut self, request: T) -> Result { 63 | self(request).map_err(Into::into) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /tower/src/hedge/delay.rs: -------------------------------------------------------------------------------- 1 | use pin_project_lite::pin_project; 2 | use std::time::Duration; 3 | use std::{ 4 | future::Future, 5 | pin::Pin, 6 | task::{ready, Context, Poll}, 7 | }; 8 | use tower_service::Service; 9 | 10 | use crate::util::Oneshot; 11 | 12 | /// A policy which specifies how long each request should be delayed for. 13 | pub trait Policy { 14 | fn delay(&self, req: &Request) -> Duration; 15 | } 16 | 17 | /// A middleware which delays sending the request to the underlying service 18 | /// for an amount of time specified by the policy. 19 | #[derive(Debug)] 20 | pub struct Delay { 21 | policy: P, 22 | service: S, 23 | } 24 | 25 | pin_project! { 26 | #[derive(Debug)] 27 | pub struct ResponseFuture 28 | where 29 | S: Service, 30 | { 31 | service: Option, 32 | #[pin] 33 | state: State>, 34 | } 35 | } 36 | 37 | pin_project! { 38 | #[project = StateProj] 39 | #[derive(Debug)] 40 | enum State { 41 | Delaying { 42 | #[pin] 43 | delay: tokio::time::Sleep, 44 | req: Option, 45 | }, 46 | Called { 47 | #[pin] 48 | fut: F, 49 | }, 50 | } 51 | } 52 | 53 | impl State { 54 | fn delaying(delay: tokio::time::Sleep, req: Option) -> Self { 55 | Self::Delaying { delay, req } 56 | } 57 | 58 | fn called(fut: F) -> Self { 59 | Self::Called { fut } 60 | } 61 | } 62 | 63 | impl Delay { 64 | pub const fn new(policy: P, service: S) -> Self 65 | where 66 | P: Policy, 67 | S: Service + Clone, 68 | S::Error: Into, 69 | { 70 | Delay { policy, service } 71 | } 72 | } 73 | 74 | impl Service for Delay 75 | where 76 | P: Policy, 77 | S: Service + Clone, 78 | S::Error: Into, 79 | { 80 | type Response = S::Response; 81 | type Error = crate::BoxError; 82 | type Future = ResponseFuture; 83 | 84 | fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { 85 | // Calling self.service.poll_ready would reserve a slot for the delayed request, 86 | // potentially well in advance of actually making it. Instead, signal readiness here and 87 | // treat the service as a Oneshot in the future. 88 | Poll::Ready(Ok(())) 89 | } 90 | 91 | fn call(&mut self, request: Request) -> Self::Future { 92 | let delay = self.policy.delay(&request); 93 | ResponseFuture { 94 | service: Some(self.service.clone()), 95 | state: State::delaying(tokio::time::sleep(delay), Some(request)), 96 | } 97 | } 98 | } 99 | 100 | impl Future for ResponseFuture 101 | where 102 | E: Into, 103 | S: Service, 104 | { 105 | type Output = Result; 106 | 107 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 108 | let mut this = self.project(); 109 | 110 | loop { 111 | match this.state.as_mut().project() { 112 | StateProj::Delaying { delay, req } => { 113 | ready!(delay.poll(cx)); 114 | let req = req.take().expect("Missing request in delay"); 115 | let svc = this.service.take().expect("Missing service in delay"); 116 | let fut = Oneshot::new(svc, req); 117 | this.state.set(State::called(fut)); 118 | } 119 | StateProj::Called { fut } => { 120 | return fut.poll(cx).map_err(Into::into); 121 | } 122 | }; 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /tower/src/hedge/latency.rs: -------------------------------------------------------------------------------- 1 | use pin_project_lite::pin_project; 2 | use std::time::Duration; 3 | use std::{ 4 | future::Future, 5 | pin::Pin, 6 | task::{ready, Context, Poll}, 7 | }; 8 | use tokio::time::Instant; 9 | use tower_service::Service; 10 | 11 | /// Record is the interface for accepting request latency measurements. When 12 | /// a request completes, record is called with the elapsed duration between 13 | /// when the service was called and when the future completed. 14 | pub trait Record { 15 | fn record(&mut self, latency: Duration); 16 | } 17 | 18 | /// Latency is a middleware that measures request latency and records it to the 19 | /// provided Record instance. 20 | #[derive(Clone, Debug)] 21 | pub struct Latency { 22 | rec: R, 23 | service: S, 24 | } 25 | 26 | pin_project! { 27 | #[derive(Debug)] 28 | pub struct ResponseFuture { 29 | start: Instant, 30 | rec: R, 31 | #[pin] 32 | inner: F, 33 | } 34 | } 35 | 36 | impl Latency 37 | where 38 | R: Record + Clone, 39 | { 40 | pub const fn new(rec: R, service: S) -> Self 41 | where 42 | S: Service, 43 | S::Error: Into, 44 | { 45 | Latency { rec, service } 46 | } 47 | } 48 | 49 | impl Service for Latency 50 | where 51 | S: Service, 52 | S::Error: Into, 53 | R: Record + Clone, 54 | { 55 | type Response = S::Response; 56 | type Error = crate::BoxError; 57 | type Future = ResponseFuture; 58 | 59 | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { 60 | self.service.poll_ready(cx).map_err(Into::into) 61 | } 62 | 63 | fn call(&mut self, request: Request) -> Self::Future { 64 | ResponseFuture { 65 | start: Instant::now(), 66 | rec: self.rec.clone(), 67 | inner: self.service.call(request), 68 | } 69 | } 70 | } 71 | 72 | impl Future for ResponseFuture 73 | where 74 | R: Record, 75 | F: Future>, 76 | E: Into, 77 | { 78 | type Output = Result; 79 | 80 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 81 | let this = self.project(); 82 | 83 | let rsp = ready!(this.inner.poll(cx)).map_err(Into::into)?; 84 | let duration = Instant::now().saturating_duration_since(*this.start); 85 | this.rec.record(duration); 86 | Poll::Ready(Ok(rsp)) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /tower/src/hedge/rotating_histogram.rs: -------------------------------------------------------------------------------- 1 | use hdrhistogram::Histogram; 2 | use std::time::Duration; 3 | use tokio::time::Instant; 4 | use tracing::trace; 5 | 6 | /// This represents a "rotating" histogram which stores two histogram, one which 7 | /// should be read and one which should be written to. Every period, the read 8 | /// histogram is discarded and replaced by the write histogram. The idea here 9 | /// is that the read histogram should always contain a full period (the previous 10 | /// period) of write operations. 11 | #[derive(Debug)] 12 | pub struct RotatingHistogram { 13 | read: Histogram, 14 | write: Histogram, 15 | last_rotation: Instant, 16 | period: Duration, 17 | } 18 | 19 | impl RotatingHistogram { 20 | pub fn new(period: Duration) -> RotatingHistogram { 21 | RotatingHistogram { 22 | // Use an auto-resizing histogram to avoid choosing 23 | // a maximum latency bound for all users. 24 | read: Histogram::::new(3).expect("Invalid histogram params"), 25 | write: Histogram::::new(3).expect("Invalid histogram params"), 26 | last_rotation: Instant::now(), 27 | period, 28 | } 29 | } 30 | 31 | pub fn read(&mut self) -> &mut Histogram { 32 | self.maybe_rotate(); 33 | &mut self.read 34 | } 35 | 36 | pub fn write(&mut self) -> &mut Histogram { 37 | self.maybe_rotate(); 38 | &mut self.write 39 | } 40 | 41 | fn maybe_rotate(&mut self) { 42 | let delta = Instant::now().saturating_duration_since(self.last_rotation); 43 | // TODO: replace with delta.duration_div when it becomes stable. 44 | let rotations = (nanos(delta) / nanos(self.period)) as u32; 45 | if rotations >= 2 { 46 | trace!("Time since last rotation is {:?}. clearing!", delta); 47 | self.clear(); 48 | } else if rotations == 1 { 49 | trace!("Time since last rotation is {:?}. rotating!", delta); 50 | self.rotate(); 51 | } 52 | self.last_rotation += self.period * rotations; 53 | } 54 | 55 | fn rotate(&mut self) { 56 | std::mem::swap(&mut self.read, &mut self.write); 57 | trace!("Rotated {:?} points into read", self.read.len()); 58 | self.write.clear(); 59 | } 60 | 61 | fn clear(&mut self) { 62 | self.read.clear(); 63 | self.write.clear(); 64 | } 65 | } 66 | 67 | const NANOS_PER_SEC: u64 = 1_000_000_000; 68 | fn nanos(duration: Duration) -> u64 { 69 | duration 70 | .as_secs() 71 | .saturating_mul(NANOS_PER_SEC) 72 | .saturating_add(u64::from(duration.subsec_nanos())) 73 | } 74 | -------------------------------------------------------------------------------- /tower/src/hedge/select.rs: -------------------------------------------------------------------------------- 1 | use pin_project_lite::pin_project; 2 | use std::{ 3 | future::Future, 4 | pin::Pin, 5 | task::{Context, Poll}, 6 | }; 7 | use tower_service::Service; 8 | 9 | /// A policy which decides which requests can be cloned and sent to the B 10 | /// service. 11 | pub trait Policy { 12 | fn clone_request(&self, req: &Request) -> Option; 13 | } 14 | 15 | /// Select is a middleware which attempts to clone the request and sends the 16 | /// original request to the A service and, if the request was able to be cloned, 17 | /// the cloned request to the B service. Both resulting futures will be polled 18 | /// and whichever future completes first will be used as the result. 19 | #[derive(Debug)] 20 | pub struct Select { 21 | policy: P, 22 | a: A, 23 | b: B, 24 | } 25 | 26 | pin_project! { 27 | #[derive(Debug)] 28 | pub struct ResponseFuture { 29 | #[pin] 30 | a_fut: AF, 31 | #[pin] 32 | b_fut: Option, 33 | } 34 | } 35 | 36 | impl Select { 37 | pub const fn new(policy: P, a: A, b: B) -> Self 38 | where 39 | P: Policy, 40 | A: Service, 41 | A::Error: Into, 42 | B: Service, 43 | B::Error: Into, 44 | { 45 | Select { policy, a, b } 46 | } 47 | } 48 | 49 | impl Service for Select 50 | where 51 | P: Policy, 52 | A: Service, 53 | A::Error: Into, 54 | B: Service, 55 | B::Error: Into, 56 | { 57 | type Response = A::Response; 58 | type Error = crate::BoxError; 59 | type Future = ResponseFuture; 60 | 61 | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { 62 | match (self.a.poll_ready(cx), self.b.poll_ready(cx)) { 63 | (Poll::Ready(Ok(())), Poll::Ready(Ok(()))) => Poll::Ready(Ok(())), 64 | (Poll::Ready(Err(e)), _) => Poll::Ready(Err(e.into())), 65 | (_, Poll::Ready(Err(e))) => Poll::Ready(Err(e.into())), 66 | _ => Poll::Pending, 67 | } 68 | } 69 | 70 | fn call(&mut self, request: Request) -> Self::Future { 71 | let b_fut = if let Some(cloned_req) = self.policy.clone_request(&request) { 72 | Some(self.b.call(cloned_req)) 73 | } else { 74 | None 75 | }; 76 | ResponseFuture { 77 | a_fut: self.a.call(request), 78 | b_fut, 79 | } 80 | } 81 | } 82 | 83 | impl Future for ResponseFuture 84 | where 85 | AF: Future>, 86 | AE: Into, 87 | BF: Future>, 88 | BE: Into, 89 | { 90 | type Output = Result; 91 | 92 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 93 | let this = self.project(); 94 | 95 | if let Poll::Ready(r) = this.a_fut.poll(cx) { 96 | return Poll::Ready(Ok(r.map_err(Into::into)?)); 97 | } 98 | if let Some(b_fut) = this.b_fut.as_pin_mut() { 99 | if let Poll::Ready(r) = b_fut.poll(cx) { 100 | return Poll::Ready(Ok(r.map_err(Into::into)?)); 101 | } 102 | } 103 | Poll::Pending 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /tower/src/layer.rs: -------------------------------------------------------------------------------- 1 | //! A collection of [`Layer`] based tower services 2 | //! 3 | //! [`Layer`]: crate::Layer 4 | 5 | pub use tower_layer::{layer_fn, Layer, LayerFn}; 6 | 7 | /// Utilities for combining layers 8 | /// 9 | /// [`Identity`]: crate::layer::util::Identity 10 | /// [`Layer`]: crate::Layer 11 | /// [`Stack`]: crate::layer::util::Stack 12 | pub mod util { 13 | pub use tower_layer::{Identity, Stack}; 14 | } 15 | -------------------------------------------------------------------------------- /tower/src/limit/concurrency/future.rs: -------------------------------------------------------------------------------- 1 | //! [`Future`] types 2 | //! 3 | //! [`Future`]: std::future::Future 4 | use pin_project_lite::pin_project; 5 | use std::{ 6 | future::Future, 7 | pin::Pin, 8 | task::{ready, Context, Poll}, 9 | }; 10 | use tokio::sync::OwnedSemaphorePermit; 11 | 12 | pin_project! { 13 | /// Future for the [`ConcurrencyLimit`] service. 14 | /// 15 | /// [`ConcurrencyLimit`]: crate::limit::ConcurrencyLimit 16 | #[derive(Debug)] 17 | pub struct ResponseFuture { 18 | #[pin] 19 | inner: T, 20 | // Keep this around so that it is dropped when the future completes 21 | _permit: OwnedSemaphorePermit, 22 | } 23 | } 24 | 25 | impl ResponseFuture { 26 | pub(crate) fn new(inner: T, _permit: OwnedSemaphorePermit) -> ResponseFuture { 27 | ResponseFuture { inner, _permit } 28 | } 29 | } 30 | 31 | impl Future for ResponseFuture 32 | where 33 | F: Future>, 34 | { 35 | type Output = Result; 36 | 37 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 38 | Poll::Ready(ready!(self.project().inner.poll(cx))) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tower/src/limit/concurrency/layer.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use super::ConcurrencyLimit; 4 | use tokio::sync::Semaphore; 5 | use tower_layer::Layer; 6 | 7 | /// Enforces a limit on the concurrent number of requests the underlying 8 | /// service can handle. 9 | #[derive(Debug, Clone)] 10 | pub struct ConcurrencyLimitLayer { 11 | max: usize, 12 | } 13 | 14 | impl ConcurrencyLimitLayer { 15 | /// Create a new concurrency limit layer. 16 | pub const fn new(max: usize) -> Self { 17 | ConcurrencyLimitLayer { max } 18 | } 19 | } 20 | 21 | impl Layer for ConcurrencyLimitLayer { 22 | type Service = ConcurrencyLimit; 23 | 24 | fn layer(&self, service: S) -> Self::Service { 25 | ConcurrencyLimit::new(service, self.max) 26 | } 27 | } 28 | 29 | /// Enforces a limit on the concurrent number of requests the underlying 30 | /// service can handle. 31 | /// 32 | /// Unlike [`ConcurrencyLimitLayer`], which enforces a per-service concurrency 33 | /// limit, this layer accepts a owned semaphore (`Arc`) which can be 34 | /// shared across multiple services. 35 | /// 36 | /// Cloning this layer will not create a new semaphore. 37 | #[derive(Debug, Clone)] 38 | pub struct GlobalConcurrencyLimitLayer { 39 | semaphore: Arc, 40 | } 41 | 42 | impl GlobalConcurrencyLimitLayer { 43 | /// Create a new `GlobalConcurrencyLimitLayer`. 44 | pub fn new(max: usize) -> Self { 45 | Self::with_semaphore(Arc::new(Semaphore::new(max))) 46 | } 47 | 48 | /// Create a new `GlobalConcurrencyLimitLayer` from a `Arc` 49 | pub fn with_semaphore(semaphore: Arc) -> Self { 50 | GlobalConcurrencyLimitLayer { semaphore } 51 | } 52 | } 53 | 54 | impl Layer for GlobalConcurrencyLimitLayer { 55 | type Service = ConcurrencyLimit; 56 | 57 | fn layer(&self, service: S) -> Self::Service { 58 | ConcurrencyLimit::with_semaphore(service, self.semaphore.clone()) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /tower/src/limit/concurrency/mod.rs: -------------------------------------------------------------------------------- 1 | //! Limit the max number of requests being concurrently processed. 2 | 3 | pub mod future; 4 | mod layer; 5 | mod service; 6 | 7 | pub use self::{ 8 | layer::{ConcurrencyLimitLayer, GlobalConcurrencyLimitLayer}, 9 | service::ConcurrencyLimit, 10 | }; 11 | -------------------------------------------------------------------------------- /tower/src/limit/concurrency/service.rs: -------------------------------------------------------------------------------- 1 | use super::future::ResponseFuture; 2 | use tokio::sync::{OwnedSemaphorePermit, Semaphore}; 3 | use tokio_util::sync::PollSemaphore; 4 | use tower_service::Service; 5 | 6 | use std::{ 7 | sync::Arc, 8 | task::{ready, Context, Poll}, 9 | }; 10 | 11 | /// Enforces a limit on the concurrent number of requests the underlying 12 | /// service can handle. 13 | #[derive(Debug)] 14 | pub struct ConcurrencyLimit { 15 | inner: T, 16 | semaphore: PollSemaphore, 17 | /// The currently acquired semaphore permit, if there is sufficient 18 | /// concurrency to send a new request. 19 | /// 20 | /// The permit is acquired in `poll_ready`, and taken in `call` when sending 21 | /// a new request. 22 | permit: Option, 23 | } 24 | 25 | impl ConcurrencyLimit { 26 | /// Create a new concurrency limiter. 27 | pub fn new(inner: T, max: usize) -> Self { 28 | Self::with_semaphore(inner, Arc::new(Semaphore::new(max))) 29 | } 30 | 31 | /// Create a new concurrency limiter with a provided shared semaphore 32 | pub fn with_semaphore(inner: T, semaphore: Arc) -> Self { 33 | ConcurrencyLimit { 34 | inner, 35 | semaphore: PollSemaphore::new(semaphore), 36 | permit: None, 37 | } 38 | } 39 | 40 | /// Get a reference to the inner service 41 | pub fn get_ref(&self) -> &T { 42 | &self.inner 43 | } 44 | 45 | /// Get a mutable reference to the inner service 46 | pub fn get_mut(&mut self) -> &mut T { 47 | &mut self.inner 48 | } 49 | 50 | /// Consume `self`, returning the inner service 51 | pub fn into_inner(self) -> T { 52 | self.inner 53 | } 54 | } 55 | 56 | impl Service for ConcurrencyLimit 57 | where 58 | S: Service, 59 | { 60 | type Response = S::Response; 61 | type Error = S::Error; 62 | type Future = ResponseFuture; 63 | 64 | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { 65 | // If we haven't already acquired a permit from the semaphore, try to 66 | // acquire one first. 67 | if self.permit.is_none() { 68 | self.permit = ready!(self.semaphore.poll_acquire(cx)); 69 | debug_assert!( 70 | self.permit.is_some(), 71 | "ConcurrencyLimit semaphore is never closed, so `poll_acquire` \ 72 | should never fail", 73 | ); 74 | } 75 | 76 | // Once we've acquired a permit (or if we already had one), poll the 77 | // inner service. 78 | self.inner.poll_ready(cx) 79 | } 80 | 81 | fn call(&mut self, request: Request) -> Self::Future { 82 | // Take the permit 83 | let permit = self 84 | .permit 85 | .take() 86 | .expect("max requests in-flight; poll_ready must be called first"); 87 | 88 | // Call the inner service 89 | let future = self.inner.call(request); 90 | 91 | ResponseFuture::new(future, permit) 92 | } 93 | } 94 | 95 | impl Clone for ConcurrencyLimit { 96 | fn clone(&self) -> Self { 97 | // Since we hold an `OwnedSemaphorePermit`, we can't derive `Clone`. 98 | // Instead, when cloning the service, create a new service with the 99 | // same semaphore, but with the permit in the un-acquired state. 100 | Self { 101 | inner: self.inner.clone(), 102 | semaphore: self.semaphore.clone(), 103 | permit: None, 104 | } 105 | } 106 | } 107 | 108 | #[cfg(feature = "load")] 109 | impl crate::load::Load for ConcurrencyLimit 110 | where 111 | S: crate::load::Load, 112 | { 113 | type Metric = S::Metric; 114 | fn load(&self) -> Self::Metric { 115 | self.inner.load() 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /tower/src/limit/mod.rs: -------------------------------------------------------------------------------- 1 | //! Tower middleware for limiting requests. 2 | 3 | pub mod concurrency; 4 | pub mod rate; 5 | 6 | pub use self::{ 7 | concurrency::{ConcurrencyLimit, ConcurrencyLimitLayer, GlobalConcurrencyLimitLayer}, 8 | rate::{RateLimit, RateLimitLayer}, 9 | }; 10 | -------------------------------------------------------------------------------- /tower/src/limit/rate/layer.rs: -------------------------------------------------------------------------------- 1 | use super::{Rate, RateLimit}; 2 | use std::time::Duration; 3 | use tower_layer::Layer; 4 | 5 | /// Enforces a rate limit on the number of requests the underlying 6 | /// service can handle over a period of time. 7 | #[derive(Debug, Clone)] 8 | pub struct RateLimitLayer { 9 | rate: Rate, 10 | } 11 | 12 | impl RateLimitLayer { 13 | /// Create new rate limit layer. 14 | pub const fn new(num: u64, per: Duration) -> Self { 15 | let rate = Rate::new(num, per); 16 | RateLimitLayer { rate } 17 | } 18 | } 19 | 20 | impl Layer for RateLimitLayer { 21 | type Service = RateLimit; 22 | 23 | fn layer(&self, service: S) -> Self::Service { 24 | RateLimit::new(service, self.rate) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tower/src/limit/rate/mod.rs: -------------------------------------------------------------------------------- 1 | //! Limit the rate at which requests are processed. 2 | 3 | mod layer; 4 | #[allow(clippy::module_inception)] 5 | mod rate; 6 | mod service; 7 | 8 | pub use self::{layer::RateLimitLayer, rate::Rate, service::RateLimit}; 9 | -------------------------------------------------------------------------------- /tower/src/limit/rate/rate.rs: -------------------------------------------------------------------------------- 1 | use std::time::Duration; 2 | 3 | /// A rate of requests per time period. 4 | #[derive(Debug, Copy, Clone)] 5 | pub struct Rate { 6 | num: u64, 7 | per: Duration, 8 | } 9 | 10 | impl Rate { 11 | /// Create a new rate. 12 | /// 13 | /// # Panics 14 | /// 15 | /// This function panics if `num` or `per` is 0. 16 | pub const fn new(num: u64, per: Duration) -> Self { 17 | assert!(num > 0); 18 | assert!(per.as_nanos() > 0); 19 | 20 | Rate { num, per } 21 | } 22 | 23 | pub(crate) fn num(&self) -> u64 { 24 | self.num 25 | } 26 | 27 | pub(crate) fn per(&self) -> Duration { 28 | self.per 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tower/src/load/completion.rs: -------------------------------------------------------------------------------- 1 | //! Application-specific request completion semantics. 2 | 3 | use pin_project_lite::pin_project; 4 | use std::{ 5 | future::Future, 6 | pin::Pin, 7 | task::{ready, Context, Poll}, 8 | }; 9 | 10 | /// Attaches `H`-typed completion tracker to `V` typed values. 11 | /// 12 | /// Handles (of type `H`) are intended to be RAII guards that primarily implement [`Drop`] and update 13 | /// load metric state as they are dropped. This trait allows implementors to "forward" the handle 14 | /// to later parts of the request-handling pipeline, so that the handle is only dropped when the 15 | /// request has truly completed. 16 | /// 17 | /// This utility allows load metrics to have a protocol-agnostic means to track streams past their 18 | /// initial response future. For example, if `V` represents an HTTP response type, an 19 | /// implementation could add `H`-typed handles to each response's extensions to detect when all the 20 | /// response's extensions have been dropped. 21 | /// 22 | /// A base `impl TrackCompletion for CompleteOnResponse` is provided to drop the handle 23 | /// once the response future is resolved. This is appropriate when a response is discrete and 24 | /// cannot comprise multiple messages. 25 | /// 26 | /// In many cases, the `Output` type is simply `V`. However, [`TrackCompletion`] may alter the type 27 | /// in order to instrument it appropriately. For example, an HTTP [`TrackCompletion`] may modify 28 | /// the body type: so a [`TrackCompletion`] that takes values of type 29 | /// [`http::Response`][response] may output values of type [`http::Response`][response]. 30 | /// 31 | /// [response]: https://docs.rs/http/latest/http/response/struct.Response.html 32 | pub trait TrackCompletion: Clone { 33 | /// The instrumented value type. 34 | type Output; 35 | 36 | /// Attaches a `H`-typed handle to a `V`-typed value. 37 | fn track_completion(&self, handle: H, value: V) -> Self::Output; 38 | } 39 | 40 | /// A [`TrackCompletion`] implementation that considers the request completed when the response 41 | /// future is resolved. 42 | #[derive(Clone, Copy, Debug, Default)] 43 | #[non_exhaustive] 44 | pub struct CompleteOnResponse; 45 | 46 | pin_project! { 47 | /// Attaches a `C`-typed completion tracker to the result of an `F`-typed [`Future`]. 48 | #[derive(Debug)] 49 | pub struct TrackCompletionFuture { 50 | #[pin] 51 | future: F, 52 | handle: Option, 53 | completion: C, 54 | } 55 | } 56 | 57 | // ===== impl InstrumentFuture ===== 58 | 59 | impl TrackCompletionFuture { 60 | /// Wraps a future, propagating the tracker into its value if successful. 61 | pub const fn new(completion: C, handle: H, future: F) -> Self { 62 | TrackCompletionFuture { 63 | future, 64 | completion, 65 | handle: Some(handle), 66 | } 67 | } 68 | } 69 | 70 | impl Future for TrackCompletionFuture 71 | where 72 | F: Future>, 73 | C: TrackCompletion, 74 | { 75 | type Output = Result; 76 | 77 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 78 | let this = self.project(); 79 | let rsp = ready!(this.future.poll(cx))?; 80 | let h = this.handle.take().expect("handle"); 81 | Poll::Ready(Ok(this.completion.track_completion(h, rsp))) 82 | } 83 | } 84 | 85 | // ===== CompleteOnResponse ===== 86 | 87 | impl TrackCompletion for CompleteOnResponse { 88 | type Output = V; 89 | 90 | fn track_completion(&self, handle: H, value: V) -> V { 91 | drop(handle); 92 | value 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /tower/src/load/constant.rs: -------------------------------------------------------------------------------- 1 | //! A constant [`Load`] implementation. 2 | 3 | #[cfg(feature = "discover")] 4 | use crate::discover::{Change, Discover}; 5 | #[cfg(feature = "discover")] 6 | use futures_core::Stream; 7 | #[cfg(feature = "discover")] 8 | use std::{pin::Pin, task::ready}; 9 | 10 | use super::Load; 11 | use pin_project_lite::pin_project; 12 | use std::task::{Context, Poll}; 13 | use tower_service::Service; 14 | 15 | pin_project! { 16 | #[derive(Debug)] 17 | /// Wraps a type so that it implements [`Load`] and returns a constant load metric. 18 | /// 19 | /// This load estimator is primarily useful for testing. 20 | pub struct Constant { 21 | inner: T, 22 | load: M, 23 | } 24 | } 25 | 26 | // ===== impl Constant ===== 27 | 28 | impl Constant { 29 | /// Wraps a `T`-typed service with a constant `M`-typed load metric. 30 | pub const fn new(inner: T, load: M) -> Self { 31 | Self { inner, load } 32 | } 33 | } 34 | 35 | impl Load for Constant { 36 | type Metric = M; 37 | 38 | fn load(&self) -> M { 39 | self.load 40 | } 41 | } 42 | 43 | impl Service for Constant 44 | where 45 | S: Service, 46 | M: Copy, 47 | { 48 | type Response = S::Response; 49 | type Error = S::Error; 50 | type Future = S::Future; 51 | 52 | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { 53 | self.inner.poll_ready(cx) 54 | } 55 | 56 | fn call(&mut self, req: Request) -> Self::Future { 57 | self.inner.call(req) 58 | } 59 | } 60 | 61 | /// Proxies [`Discover`] such that all changes are wrapped with a constant load. 62 | #[cfg(feature = "discover")] 63 | impl Stream for Constant { 64 | type Item = Result>, D::Error>; 65 | 66 | /// Yields the next discovery change set. 67 | fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { 68 | use self::Change::*; 69 | 70 | let this = self.project(); 71 | let change = match ready!(Pin::new(this.inner).poll_discover(cx)).transpose()? { 72 | None => return Poll::Ready(None), 73 | Some(Insert(k, svc)) => Insert(k, Constant::new(svc, *this.load)), 74 | Some(Remove(k)) => Remove(k), 75 | }; 76 | 77 | Poll::Ready(Some(Ok(change))) 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /tower/src/load/mod.rs: -------------------------------------------------------------------------------- 1 | //! Service load measurement 2 | //! 3 | //! This module provides the [`Load`] trait, which allows measuring how loaded a service is. 4 | //! It also provides several wrapper types that measure load in different ways: 5 | //! 6 | //! - [`Constant`] — Always returns the same constant load value for a service. 7 | //! - [`PendingRequests`] — Measures load by tracking the number of in-flight requests. 8 | //! - [`PeakEwma`] — Measures load using a moving average of the peak latency for the service. 9 | //! 10 | //! In general, you will want to use one of these when using the types in [`tower::balance`] which 11 | //! balance services depending on their load. Which load metric to use depends on your exact 12 | //! use-case, but the ones above should get you quite far! 13 | //! 14 | //! When the `discover` feature is enabled, wrapper types for [`Discover`] that 15 | //! wrap the discovered services with the given load estimator are also provided. 16 | //! 17 | //! # When does a request complete? 18 | //! 19 | //! For many applications, the request life-cycle is relatively simple: when a service responds to 20 | //! a request, that request is done, and the system can forget about it. However, for some 21 | //! applications, the service may respond to the initial request while other parts of the system 22 | //! are still acting on that request. In such an application, the system load must take these 23 | //! requests into account as well, or risk the system underestimating its own load. 24 | //! 25 | //! To support these use-cases, the load estimators in this module are parameterized by the 26 | //! [`TrackCompletion`] trait, with [`CompleteOnResponse`] as the default type. The behavior of 27 | //! [`CompleteOnResponse`] is what you would normally expect for a request-response cycle: when the 28 | //! response is produced, the request is considered "finished", and load goes down. This can be 29 | //! overridden by your own user-defined type to track more complex request completion semantics. See 30 | //! the documentation for [`completion`] for more details. 31 | //! 32 | //! # Examples 33 | //! 34 | //! ```rust 35 | //! # #[cfg(feature = "util")] 36 | //! use tower::util::ServiceExt; 37 | //! # #[cfg(feature = "util")] 38 | //! use tower::{load::Load, Service}; 39 | //! # #[cfg(feature = "util")] 40 | //! async fn simple_balance( 41 | //! svc1: &mut S1, 42 | //! svc2: &mut S2, 43 | //! request: R 44 | //! ) -> Result 45 | //! where 46 | //! S1: Load + Service, 47 | //! S2: Load + Service 48 | //! { 49 | //! if svc1.load() < svc2.load() { 50 | //! svc1.ready().await?.call(request).await 51 | //! } else { 52 | //! svc2.ready().await?.call(request).await 53 | //! } 54 | //! } 55 | //! ``` 56 | //! 57 | //! [`tower::balance`]: crate::balance 58 | //! [`Discover`]: crate::discover::Discover 59 | //! [`CompleteOnResponse`]: crate::load::completion::CompleteOnResponse 60 | // TODO: a custom completion example would be good here 61 | 62 | pub mod completion; 63 | mod constant; 64 | pub mod peak_ewma; 65 | pub mod pending_requests; 66 | 67 | pub use self::{ 68 | completion::{CompleteOnResponse, TrackCompletion}, 69 | constant::Constant, 70 | peak_ewma::PeakEwma, 71 | pending_requests::PendingRequests, 72 | }; 73 | 74 | #[cfg(feature = "discover")] 75 | pub use self::{peak_ewma::PeakEwmaDiscover, pending_requests::PendingRequestsDiscover}; 76 | 77 | /// Types that implement this trait can give an estimate of how loaded they are. 78 | /// 79 | /// See the module documentation for more details. 80 | pub trait Load { 81 | /// A comparable load metric. 82 | /// 83 | /// Lesser values indicate that the service is less loaded, and should be preferred for new 84 | /// requests over another service with a higher value. 85 | type Metric: PartialOrd; 86 | 87 | /// Estimate the service's current load. 88 | fn load(&self) -> Self::Metric; 89 | } 90 | -------------------------------------------------------------------------------- /tower/src/load_shed/error.rs: -------------------------------------------------------------------------------- 1 | //! Error types 2 | 3 | use std::fmt; 4 | 5 | /// An error returned by [`LoadShed`] when the underlying service 6 | /// is not ready to handle any requests at the time of being 7 | /// called. 8 | /// 9 | /// [`LoadShed`]: crate::load_shed::LoadShed 10 | #[derive(Default)] 11 | pub struct Overloaded { 12 | _p: (), 13 | } 14 | 15 | impl Overloaded { 16 | /// Construct a new overloaded error 17 | pub const fn new() -> Self { 18 | Overloaded { _p: () } 19 | } 20 | } 21 | 22 | impl fmt::Debug for Overloaded { 23 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 24 | f.write_str("Overloaded") 25 | } 26 | } 27 | 28 | impl fmt::Display for Overloaded { 29 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 30 | f.write_str("service overloaded") 31 | } 32 | } 33 | 34 | impl std::error::Error for Overloaded {} 35 | -------------------------------------------------------------------------------- /tower/src/load_shed/future.rs: -------------------------------------------------------------------------------- 1 | //! Future types 2 | 3 | use std::fmt; 4 | use std::future::Future; 5 | use std::pin::Pin; 6 | use std::task::{ready, Context, Poll}; 7 | 8 | use pin_project_lite::pin_project; 9 | 10 | use super::error::Overloaded; 11 | 12 | pin_project! { 13 | /// Future for the [`LoadShed`] service. 14 | /// 15 | /// [`LoadShed`]: crate::load_shed::LoadShed 16 | pub struct ResponseFuture { 17 | #[pin] 18 | state: ResponseState, 19 | } 20 | } 21 | 22 | pin_project! { 23 | #[project = ResponseStateProj] 24 | enum ResponseState { 25 | Called { 26 | #[pin] 27 | fut: F 28 | }, 29 | Overloaded, 30 | } 31 | } 32 | 33 | impl ResponseFuture { 34 | pub(crate) fn called(fut: F) -> Self { 35 | ResponseFuture { 36 | state: ResponseState::Called { fut }, 37 | } 38 | } 39 | 40 | pub(crate) fn overloaded() -> Self { 41 | ResponseFuture { 42 | state: ResponseState::Overloaded, 43 | } 44 | } 45 | } 46 | 47 | impl Future for ResponseFuture 48 | where 49 | F: Future>, 50 | E: Into, 51 | { 52 | type Output = Result; 53 | 54 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 55 | match self.project().state.project() { 56 | ResponseStateProj::Called { fut } => { 57 | Poll::Ready(ready!(fut.poll(cx)).map_err(Into::into)) 58 | } 59 | ResponseStateProj::Overloaded => Poll::Ready(Err(Overloaded::new().into())), 60 | } 61 | } 62 | } 63 | 64 | impl fmt::Debug for ResponseFuture 65 | where 66 | // bounds for future-proofing... 67 | F: fmt::Debug, 68 | { 69 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 70 | f.write_str("ResponseFuture") 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /tower/src/load_shed/layer.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use tower_layer::Layer; 3 | 4 | use super::LoadShed; 5 | 6 | /// A [`Layer`] to wrap services in [`LoadShed`] middleware. 7 | /// 8 | /// [`Layer`]: crate::Layer 9 | #[derive(Clone, Default)] 10 | pub struct LoadShedLayer { 11 | _p: (), 12 | } 13 | 14 | impl LoadShedLayer { 15 | /// Creates a new layer. 16 | pub const fn new() -> Self { 17 | LoadShedLayer { _p: () } 18 | } 19 | } 20 | 21 | impl Layer for LoadShedLayer { 22 | type Service = LoadShed; 23 | 24 | fn layer(&self, service: S) -> Self::Service { 25 | LoadShed::new(service) 26 | } 27 | } 28 | 29 | impl fmt::Debug for LoadShedLayer { 30 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 31 | f.debug_struct("LoadShedLayer").finish() 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tower/src/load_shed/mod.rs: -------------------------------------------------------------------------------- 1 | //! Middleware for shedding load when inner services aren't ready. 2 | 3 | use std::task::{Context, Poll}; 4 | use tower_service::Service; 5 | 6 | pub mod error; 7 | pub mod future; 8 | mod layer; 9 | 10 | use self::future::ResponseFuture; 11 | pub use self::layer::LoadShedLayer; 12 | 13 | /// A [`Service`] that sheds load when the inner service isn't ready. 14 | /// 15 | /// [`Service`]: crate::Service 16 | #[derive(Debug)] 17 | pub struct LoadShed { 18 | inner: S, 19 | is_ready: bool, 20 | } 21 | 22 | // ===== impl LoadShed ===== 23 | 24 | impl LoadShed { 25 | /// Wraps a service in [`LoadShed`] middleware. 26 | pub const fn new(inner: S) -> Self { 27 | LoadShed { 28 | inner, 29 | is_ready: false, 30 | } 31 | } 32 | } 33 | 34 | impl Service for LoadShed 35 | where 36 | S: Service, 37 | S::Error: Into, 38 | { 39 | type Response = S::Response; 40 | type Error = crate::BoxError; 41 | type Future = ResponseFuture; 42 | 43 | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { 44 | // We check for readiness here, so that we can know in `call` if 45 | // the inner service is overloaded or not. 46 | self.is_ready = match self.inner.poll_ready(cx) { 47 | Poll::Ready(Err(e)) => return Poll::Ready(Err(e.into())), 48 | r => r.is_ready(), 49 | }; 50 | 51 | // But we always report Ready, so that layers above don't wait until 52 | // the inner service is ready (the entire point of this layer!) 53 | Poll::Ready(Ok(())) 54 | } 55 | 56 | fn call(&mut self, req: Req) -> Self::Future { 57 | if self.is_ready { 58 | // readiness only counts once, you need to check again! 59 | self.is_ready = false; 60 | ResponseFuture::called(self.inner.call(req)) 61 | } else { 62 | ResponseFuture::overloaded() 63 | } 64 | } 65 | } 66 | 67 | impl Clone for LoadShed { 68 | fn clone(&self) -> Self { 69 | LoadShed { 70 | inner: self.inner.clone(), 71 | // new clones shouldn't carry the readiness state, as a cloneable 72 | // inner service likely tracks readiness per clone. 73 | is_ready: false, 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /tower/src/macros.rs: -------------------------------------------------------------------------------- 1 | #[cfg(any( 2 | feature = "util", 3 | feature = "spawn-ready", 4 | feature = "filter", 5 | feature = "make" 6 | ))] 7 | macro_rules! opaque_future { 8 | ($(#[$m:meta])* pub type $name:ident<$($param:ident),+> = $actual:ty;) => { 9 | pin_project_lite::pin_project! { 10 | $(#[$m])* 11 | pub struct $name<$($param),+> { 12 | #[pin] 13 | inner: $actual 14 | } 15 | } 16 | 17 | impl<$($param),+> $name<$($param),+> { 18 | pub(crate) fn new(inner: $actual) -> Self { 19 | Self { 20 | inner 21 | } 22 | } 23 | } 24 | 25 | impl<$($param),+> std::fmt::Debug for $name<$($param),+> { 26 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 27 | f.debug_tuple(stringify!($name)).field(&format_args!("...")).finish() 28 | } 29 | } 30 | 31 | impl<$($param),+> std::future::Future for $name<$($param),+> 32 | where 33 | $actual: std::future::Future, 34 | { 35 | type Output = <$actual as std::future::Future>::Output; 36 | #[inline] 37 | fn poll(self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> std::task::Poll { 38 | self.project().inner.poll(cx) 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tower/src/make/make_connection.rs: -------------------------------------------------------------------------------- 1 | use crate::sealed::Sealed; 2 | use std::future::Future; 3 | use std::task::{Context, Poll}; 4 | use tokio::io::{AsyncRead, AsyncWrite}; 5 | use tower_service::Service; 6 | 7 | /// The [`MakeConnection`] trait is used to create transports. 8 | /// 9 | /// The goal of this service is to allow composable methods for creating 10 | /// `AsyncRead + AsyncWrite` transports. This could mean creating a TLS 11 | /// based connection or using some other method to authenticate the connection. 12 | pub trait MakeConnection: Sealed<(Target,)> { 13 | /// The transport provided by this service 14 | type Connection: AsyncRead + AsyncWrite; 15 | 16 | /// Errors produced by the connecting service 17 | type Error; 18 | 19 | /// The future that eventually produces the transport 20 | type Future: Future>; 21 | 22 | /// Returns `Poll::Ready(Ok(()))` when it is able to make more connections. 23 | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll>; 24 | 25 | /// Connect and return a transport asynchronously 26 | fn make_connection(&mut self, target: Target) -> Self::Future; 27 | } 28 | 29 | impl Sealed<(Target,)> for S where S: Service {} 30 | 31 | impl MakeConnection for C 32 | where 33 | C: Service, 34 | C::Response: AsyncRead + AsyncWrite, 35 | { 36 | type Connection = C::Response; 37 | type Error = C::Error; 38 | type Future = C::Future; 39 | 40 | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { 41 | Service::poll_ready(self, cx) 42 | } 43 | 44 | fn make_connection(&mut self, target: Target) -> Self::Future { 45 | Service::call(self, target) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tower/src/make/mod.rs: -------------------------------------------------------------------------------- 1 | //! Trait aliases for Services that produce specific types of Responses. 2 | 3 | mod make_connection; 4 | mod make_service; 5 | 6 | pub use self::make_connection::MakeConnection; 7 | pub use self::make_service::shared::Shared; 8 | pub use self::make_service::{AsService, IntoService, MakeService}; 9 | 10 | pub mod future { 11 | //! Future types 12 | 13 | pub use super::make_service::shared::SharedFuture; 14 | } 15 | -------------------------------------------------------------------------------- /tower/src/ready_cache/error.rs: -------------------------------------------------------------------------------- 1 | //! Errors 2 | 3 | /// An error indicating that the service with a `K`-typed key failed with an 4 | /// error. 5 | pub struct Failed(pub K, pub crate::BoxError); 6 | 7 | // === Failed === 8 | 9 | impl std::fmt::Debug for Failed { 10 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 11 | f.debug_tuple("Failed") 12 | .field(&self.0) 13 | .field(&self.1) 14 | .finish() 15 | } 16 | } 17 | 18 | impl std::fmt::Display for Failed { 19 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 20 | self.1.fmt(f) 21 | } 22 | } 23 | 24 | impl std::error::Error for Failed { 25 | fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { 26 | Some(&*self.1) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tower/src/ready_cache/mod.rs: -------------------------------------------------------------------------------- 1 | //! A cache of services 2 | 3 | pub mod cache; 4 | pub mod error; 5 | 6 | pub use self::cache::ReadyCache; 7 | -------------------------------------------------------------------------------- /tower/src/reconnect/future.rs: -------------------------------------------------------------------------------- 1 | use pin_project_lite::pin_project; 2 | use std::{ 3 | future::Future, 4 | pin::Pin, 5 | task::{Context, Poll}, 6 | }; 7 | 8 | pin_project! { 9 | /// Future that resolves to the response or failure to connect. 10 | #[derive(Debug)] 11 | pub struct ResponseFuture { 12 | #[pin] 13 | inner: Inner, 14 | } 15 | } 16 | 17 | pin_project! { 18 | #[project = InnerProj] 19 | #[derive(Debug)] 20 | enum Inner { 21 | Future { 22 | #[pin] 23 | fut: F, 24 | }, 25 | Error { 26 | error: Option, 27 | }, 28 | } 29 | } 30 | 31 | impl Inner { 32 | fn future(fut: F) -> Self { 33 | Self::Future { fut } 34 | } 35 | 36 | fn error(error: Option) -> Self { 37 | Self::Error { error } 38 | } 39 | } 40 | 41 | impl ResponseFuture { 42 | pub(crate) fn new(inner: F) -> Self { 43 | ResponseFuture { 44 | inner: Inner::future(inner), 45 | } 46 | } 47 | 48 | pub(crate) fn error(error: E) -> Self { 49 | ResponseFuture { 50 | inner: Inner::error(Some(error)), 51 | } 52 | } 53 | } 54 | 55 | impl Future for ResponseFuture 56 | where 57 | F: Future>, 58 | E: Into, 59 | ME: Into, 60 | { 61 | type Output = Result; 62 | 63 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 64 | let me = self.project(); 65 | match me.inner.project() { 66 | InnerProj::Future { fut } => fut.poll(cx).map_err(Into::into), 67 | InnerProj::Error { error } => { 68 | let e = error.take().expect("Polled after ready.").into(); 69 | Poll::Ready(Err(e)) 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /tower/src/retry/budget/mod.rs: -------------------------------------------------------------------------------- 1 | //! A retry "budget" for allowing only a certain amount of retries over time. 2 | //! 3 | //! # Why budgets and not max retries? 4 | //! 5 | //! The most common way of configuring retries is to specify a maximum 6 | //! number of retry attempts to perform before giving up. This is a familiar idea to anyone 7 | //! who’s used a web browser: you try to load a webpage, and if it doesn’t load, you try again. 8 | //! If it still doesn’t load, you try a third time. Finally you give up. 9 | //! 10 | //! Unfortunately, there are at least two problems with configuring retries this way: 11 | //! 12 | //! **Choosing the maximum number of retry attempts is a guessing game.** 13 | //! You need to pick a number that’s high enough to make a difference when things are somewhat failing, 14 | //! but not so high that it generates extra load on the system when it’s really failing. In practice, 15 | //! you usually pick a maximum retry attempts number out of a hat (e.g. 3) and hope for the best. 16 | //! 17 | //! **Systems configured this way are vulnerable to retry storms.** 18 | //! A retry storm begins when one service starts to experience a larger than normal failure rate. 19 | //! This causes its clients to retry those failed requests. The extra load from the retries causes the 20 | //! service to slow down further and fail more requests, triggering more retries. If each client is 21 | //! configured to retry up to 3 times, this can quadruple the number of requests being sent! To make 22 | //! matters even worse, if any of the clients’ clients are configured with retries, the number of retries 23 | //! compounds multiplicatively and can turn a small number of errors into a self-inflicted denial of service attack. 24 | //! 25 | //! It's generally dangerous to implement retries without some limiting factor. [`Budget`]s are that limit. 26 | //! 27 | //! # Examples 28 | //! 29 | //! ```rust 30 | //! use std::{future, sync::Arc}; 31 | //! 32 | //! use tower::retry::{budget::{Budget, TpsBudget}, Policy}; 33 | //! 34 | //! type Req = String; 35 | //! type Res = String; 36 | //! 37 | //! #[derive(Clone, Debug)] 38 | //! struct RetryPolicy { 39 | //! budget: Arc, 40 | //! } 41 | //! 42 | //! impl Policy for RetryPolicy { 43 | //! type Future = future::Ready<()>; 44 | //! 45 | //! fn retry(&mut self, req: &mut Req, result: &mut Result) -> Option { 46 | //! match result { 47 | //! Ok(_) => { 48 | //! // Treat all `Response`s as success, 49 | //! // so deposit budget and don't retry... 50 | //! self.budget.deposit(); 51 | //! None 52 | //! } 53 | //! Err(_) => { 54 | //! // Treat all errors as failures... 55 | //! // Withdraw the budget, don't retry if we overdrew. 56 | //! let withdrew = self.budget.withdraw(); 57 | //! if !withdrew { 58 | //! return None; 59 | //! } 60 | //! 61 | //! // Try again! 62 | //! Some(future::ready(())) 63 | //! } 64 | //! } 65 | //! } 66 | //! 67 | //! fn clone_request(&mut self, req: &Req) -> Option { 68 | //! Some(req.clone()) 69 | //! } 70 | //! } 71 | //! ``` 72 | 73 | pub mod tps_budget; 74 | 75 | pub use tps_budget::TpsBudget; 76 | 77 | /// For more info about [`Budget`], please see the [module-level documentation]. 78 | /// 79 | /// [module-level documentation]: self 80 | pub trait Budget { 81 | /// Store a "deposit" in the budget, which will be used to permit future 82 | /// withdrawals. 83 | fn deposit(&self); 84 | 85 | /// Check whether there is enough "balance" in the budget to issue a new 86 | /// retry. 87 | /// 88 | /// If there is not enough, false is returned. 89 | fn withdraw(&self) -> bool; 90 | } 91 | -------------------------------------------------------------------------------- /tower/src/retry/layer.rs: -------------------------------------------------------------------------------- 1 | use super::Retry; 2 | use tower_layer::Layer; 3 | 4 | /// Retry requests based on a policy 5 | #[derive(Debug, Clone)] 6 | pub struct RetryLayer

{ 7 | policy: P, 8 | } 9 | 10 | impl

RetryLayer

{ 11 | /// Creates a new [`RetryLayer`] from a retry policy. 12 | pub const fn new(policy: P) -> Self { 13 | RetryLayer { policy } 14 | } 15 | } 16 | 17 | impl Layer for RetryLayer

18 | where 19 | P: Clone, 20 | { 21 | type Service = Retry; 22 | 23 | fn layer(&self, service: S) -> Self::Service { 24 | let policy = self.policy.clone(); 25 | Retry::new(policy, service) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tower/src/retry/mod.rs: -------------------------------------------------------------------------------- 1 | //! Middleware for retrying "failed" requests. 2 | 3 | pub mod backoff; 4 | pub mod budget; 5 | pub mod future; 6 | mod layer; 7 | mod policy; 8 | 9 | pub use self::layer::RetryLayer; 10 | pub use self::policy::Policy; 11 | 12 | use self::future::ResponseFuture; 13 | use pin_project_lite::pin_project; 14 | use std::task::{Context, Poll}; 15 | use tower_service::Service; 16 | 17 | pin_project! { 18 | /// Configure retrying requests of "failed" responses. 19 | /// 20 | /// A [`Policy`] classifies what is a "failed" response. 21 | /// 22 | /// # Clone 23 | /// 24 | /// This middleware requires that the inner `Service` implements [`Clone`], 25 | /// because the `Service` must be stored in each [`ResponseFuture`] in 26 | /// order to retry the request in the event of a failure. If the inner 27 | /// `Service` type does not implement `Clone`, the [`Buffer`] middleware 28 | /// can be added to make any `Service` cloneable. 29 | /// 30 | /// [`Buffer`]: crate::buffer::Buffer 31 | /// 32 | /// The `Policy` must also implement `Clone`. This middleware will 33 | /// clone the policy for each _request session_. This means a new clone 34 | /// of the policy will be created for each initial request and any subsequent 35 | /// retries of that request. Therefore, any state stored in the `Policy` instance 36 | /// is for that request session only. In order to share data across request 37 | /// sessions, that shared state may be stored in an [`Arc`], so that all clones 38 | /// of the `Policy` type reference the same instance of the shared state. 39 | /// 40 | /// [`Arc`]: std::sync::Arc 41 | #[derive(Clone, Debug)] 42 | pub struct Retry { 43 | policy: P, 44 | service: S, 45 | } 46 | } 47 | 48 | // ===== impl Retry ===== 49 | 50 | impl Retry { 51 | /// Retry the inner service depending on this [`Policy`]. 52 | pub const fn new(policy: P, service: S) -> Self { 53 | Retry { policy, service } 54 | } 55 | 56 | /// Get a reference to the inner service 57 | pub fn get_ref(&self) -> &S { 58 | &self.service 59 | } 60 | 61 | /// Get a mutable reference to the inner service 62 | pub fn get_mut(&mut self) -> &mut S { 63 | &mut self.service 64 | } 65 | 66 | /// Consume `self`, returning the inner service 67 | pub fn into_inner(self) -> S { 68 | self.service 69 | } 70 | } 71 | 72 | impl Service for Retry 73 | where 74 | P: Policy + Clone, 75 | S: Service + Clone, 76 | { 77 | type Response = S::Response; 78 | type Error = S::Error; 79 | type Future = ResponseFuture; 80 | 81 | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { 82 | // NOTE: the Future::poll impl for ResponseFuture assumes that Retry::poll_ready is 83 | // equivalent to Ready.service.poll_ready. If this ever changes, that code must be updated 84 | // as well. 85 | self.service.poll_ready(cx) 86 | } 87 | 88 | fn call(&mut self, request: Request) -> Self::Future { 89 | let cloned = self.policy.clone_request(&request); 90 | let future = self.service.call(request); 91 | 92 | ResponseFuture::new(cloned, self.clone(), future) 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /tower/src/retry/policy.rs: -------------------------------------------------------------------------------- 1 | use std::future::Future; 2 | 3 | /// A "retry policy" to classify if a request should be retried. 4 | /// 5 | /// # Example 6 | /// 7 | /// ``` 8 | /// use tower::retry::Policy; 9 | /// use std::future; 10 | /// 11 | /// type Req = String; 12 | /// type Res = String; 13 | /// 14 | /// struct Attempts(usize); 15 | /// 16 | /// impl Policy for Attempts { 17 | /// type Future = future::Ready<()>; 18 | /// 19 | /// fn retry(&mut self, req: &mut Req, result: &mut Result) -> Option { 20 | /// match result { 21 | /// Ok(_) => { 22 | /// // Treat all `Response`s as success, 23 | /// // so don't retry... 24 | /// None 25 | /// }, 26 | /// Err(_) => { 27 | /// // Treat all errors as failures... 28 | /// // But we limit the number of attempts... 29 | /// if self.0 > 0 { 30 | /// // Try again! 31 | /// self.0 -= 1; 32 | /// Some(future::ready(())) 33 | /// } else { 34 | /// // Used all our attempts, no retry... 35 | /// None 36 | /// } 37 | /// } 38 | /// } 39 | /// } 40 | /// 41 | /// fn clone_request(&mut self, req: &Req) -> Option { 42 | /// Some(req.clone()) 43 | /// } 44 | /// } 45 | /// ``` 46 | pub trait Policy { 47 | /// The [`Future`] type returned by [`Policy::retry`]. 48 | type Future: Future; 49 | 50 | /// Check the policy if a certain request should be retried. 51 | /// 52 | /// This method is passed a reference to the original request, and either 53 | /// the [`Service::Response`] or [`Service::Error`] from the inner service. 54 | /// 55 | /// If the request should **not** be retried, return `None`. 56 | /// 57 | /// If the request *should* be retried, return `Some` future that will delay 58 | /// the next retry of the request. This can be used to sleep for a certain 59 | /// duration, to wait for some external condition to be met before retrying, 60 | /// or resolve right away, if the request should be retried immediately. 61 | /// 62 | /// ## Mutating Requests 63 | /// 64 | /// The policy MAY chose to mutate the `req`: if the request is mutated, the 65 | /// mutated request will be sent to the inner service in the next retry. 66 | /// This can be helpful for use cases like tracking the retry count in a 67 | /// header. 68 | /// 69 | /// ## Mutating Results 70 | /// 71 | /// The policy MAY chose to mutate the result. This enables the retry 72 | /// policy to convert a failure into a success and vice versa. For example, 73 | /// if the policy is used to poll while waiting for a state change, the 74 | /// policy can switch the result to emit a specific error when retries are 75 | /// exhausted. 76 | /// 77 | /// The policy can also record metadata on the request to include 78 | /// information about the number of retries required or to record that a 79 | /// failure failed after exhausting all retries. 80 | /// 81 | /// [`Service::Response`]: crate::Service::Response 82 | /// [`Service::Error`]: crate::Service::Error 83 | fn retry(&mut self, req: &mut Req, result: &mut Result) -> Option; 84 | 85 | /// Tries to clone a request before being passed to the inner service. 86 | /// 87 | /// If the request cannot be cloned, return [`None`]. Moreover, the retry 88 | /// function will not be called if the [`None`] is returned. 89 | fn clone_request(&mut self, req: &Req) -> Option; 90 | } 91 | 92 | // Ensure `Policy` is object safe 93 | #[cfg(test)] 94 | fn _obj_safe(_: Box>>) {} 95 | -------------------------------------------------------------------------------- /tower/src/spawn_ready/future.rs: -------------------------------------------------------------------------------- 1 | //! Background readiness types 2 | 3 | opaque_future! { 4 | /// Response future from [`SpawnReady`] services. 5 | /// 6 | /// [`SpawnReady`]: crate::spawn_ready::SpawnReady 7 | pub type ResponseFuture = futures_util::future::MapErr crate::BoxError>; 8 | } 9 | -------------------------------------------------------------------------------- /tower/src/spawn_ready/layer.rs: -------------------------------------------------------------------------------- 1 | /// Spawns tasks to drive its inner service to readiness. 2 | #[derive(Clone, Debug, Default)] 3 | pub struct SpawnReadyLayer(()); 4 | 5 | impl SpawnReadyLayer { 6 | /// Builds a [`SpawnReadyLayer`]. 7 | pub fn new() -> Self { 8 | Self::default() 9 | } 10 | } 11 | 12 | impl tower_layer::Layer for SpawnReadyLayer { 13 | type Service = super::SpawnReady; 14 | 15 | fn layer(&self, service: S) -> Self::Service { 16 | super::SpawnReady::new(service) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tower/src/spawn_ready/mod.rs: -------------------------------------------------------------------------------- 1 | //! When an underlying service is not ready, drive it to readiness on a 2 | //! background task. 3 | 4 | pub mod future; 5 | mod layer; 6 | mod service; 7 | 8 | pub use self::layer::SpawnReadyLayer; 9 | pub use self::service::SpawnReady; 10 | -------------------------------------------------------------------------------- /tower/src/spawn_ready/service.rs: -------------------------------------------------------------------------------- 1 | use super::{future::ResponseFuture, SpawnReadyLayer}; 2 | use crate::{util::ServiceExt, BoxError}; 3 | use futures_util::future::TryFutureExt; 4 | use std::{ 5 | future::Future, 6 | pin::Pin, 7 | task::{ready, Context, Poll}, 8 | }; 9 | use tower_service::Service; 10 | use tracing::Instrument; 11 | 12 | /// Spawns tasks to drive an inner service to readiness. 13 | /// 14 | /// See crate level documentation for more details. 15 | #[derive(Debug)] 16 | pub struct SpawnReady { 17 | inner: Inner, 18 | } 19 | 20 | #[derive(Debug)] 21 | enum Inner { 22 | Service(Option), 23 | Future(tokio::task::JoinHandle>), 24 | } 25 | 26 | impl SpawnReady { 27 | /// Creates a new [`SpawnReady`] wrapping `service`. 28 | pub const fn new(service: S) -> Self { 29 | Self { 30 | inner: Inner::Service(Some(service)), 31 | } 32 | } 33 | 34 | /// Creates a layer that wraps services with [`SpawnReady`]. 35 | pub fn layer() -> SpawnReadyLayer { 36 | SpawnReadyLayer::default() 37 | } 38 | } 39 | 40 | impl Drop for SpawnReady { 41 | fn drop(&mut self) { 42 | if let Inner::Future(ref mut task) = self.inner { 43 | task.abort(); 44 | } 45 | } 46 | } 47 | 48 | impl Service for SpawnReady 49 | where 50 | Req: 'static, 51 | S: Service + Send + 'static, 52 | S::Error: Into, 53 | { 54 | type Response = S::Response; 55 | type Error = BoxError; 56 | type Future = ResponseFuture; 57 | 58 | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { 59 | loop { 60 | self.inner = match self.inner { 61 | Inner::Service(ref mut svc) => { 62 | if let Poll::Ready(r) = svc.as_mut().expect("illegal state").poll_ready(cx) { 63 | return Poll::Ready(r.map_err(Into::into)); 64 | } 65 | 66 | let svc = svc.take().expect("illegal state"); 67 | let rx = 68 | tokio::spawn(svc.ready_oneshot().map_err(Into::into).in_current_span()); 69 | Inner::Future(rx) 70 | } 71 | Inner::Future(ref mut fut) => { 72 | let svc = ready!(Pin::new(fut).poll(cx))??; 73 | Inner::Service(Some(svc)) 74 | } 75 | } 76 | } 77 | } 78 | 79 | fn call(&mut self, request: Req) -> Self::Future { 80 | match self.inner { 81 | Inner::Service(Some(ref mut svc)) => { 82 | ResponseFuture::new(svc.call(request).map_err(Into::into)) 83 | } 84 | _ => unreachable!("poll_ready must be called"), 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /tower/src/timeout/error.rs: -------------------------------------------------------------------------------- 1 | //! Error types 2 | 3 | use std::{error, fmt}; 4 | 5 | /// The timeout elapsed. 6 | #[derive(Debug, Default)] 7 | pub struct Elapsed(pub(super) ()); 8 | 9 | impl Elapsed { 10 | /// Construct a new elapsed error 11 | pub const fn new() -> Self { 12 | Elapsed(()) 13 | } 14 | } 15 | 16 | impl fmt::Display for Elapsed { 17 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 18 | f.pad("request timed out") 19 | } 20 | } 21 | 22 | impl error::Error for Elapsed {} 23 | -------------------------------------------------------------------------------- /tower/src/timeout/future.rs: -------------------------------------------------------------------------------- 1 | //! Future types 2 | 3 | use super::error::Elapsed; 4 | use pin_project_lite::pin_project; 5 | use std::{ 6 | future::Future, 7 | pin::Pin, 8 | task::{Context, Poll}, 9 | }; 10 | use tokio::time::Sleep; 11 | 12 | pin_project! { 13 | /// [`Timeout`] response future 14 | /// 15 | /// [`Timeout`]: crate::timeout::Timeout 16 | #[derive(Debug)] 17 | pub struct ResponseFuture { 18 | #[pin] 19 | response: T, 20 | #[pin] 21 | sleep: Sleep, 22 | } 23 | } 24 | 25 | impl ResponseFuture { 26 | pub(crate) fn new(response: T, sleep: Sleep) -> Self { 27 | ResponseFuture { response, sleep } 28 | } 29 | } 30 | 31 | impl Future for ResponseFuture 32 | where 33 | F: Future>, 34 | E: Into, 35 | { 36 | type Output = Result; 37 | 38 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 39 | let this = self.project(); 40 | 41 | // First, try polling the future 42 | match this.response.poll(cx) { 43 | Poll::Ready(v) => return Poll::Ready(v.map_err(Into::into)), 44 | Poll::Pending => {} 45 | } 46 | 47 | // Now check the sleep 48 | match this.sleep.poll(cx) { 49 | Poll::Pending => Poll::Pending, 50 | Poll::Ready(_) => Poll::Ready(Err(Elapsed(()).into())), 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /tower/src/timeout/layer.rs: -------------------------------------------------------------------------------- 1 | use super::Timeout; 2 | use std::time::Duration; 3 | use tower_layer::Layer; 4 | 5 | /// Applies a timeout to requests via the supplied inner service. 6 | #[derive(Debug, Clone)] 7 | pub struct TimeoutLayer { 8 | timeout: Duration, 9 | } 10 | 11 | impl TimeoutLayer { 12 | /// Create a timeout from a duration 13 | pub const fn new(timeout: Duration) -> Self { 14 | TimeoutLayer { timeout } 15 | } 16 | } 17 | 18 | impl Layer for TimeoutLayer { 19 | type Service = Timeout; 20 | 21 | fn layer(&self, service: S) -> Self::Service { 22 | Timeout::new(service, self.timeout) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tower/src/timeout/mod.rs: -------------------------------------------------------------------------------- 1 | //! Middleware that applies a timeout to requests. 2 | //! 3 | //! If the response does not complete within the specified timeout, the response 4 | //! will be aborted. 5 | 6 | pub mod error; 7 | pub mod future; 8 | mod layer; 9 | 10 | pub use self::layer::TimeoutLayer; 11 | 12 | use self::future::ResponseFuture; 13 | use std::task::{Context, Poll}; 14 | use std::time::Duration; 15 | use tower_service::Service; 16 | 17 | /// Applies a timeout to requests. 18 | #[derive(Debug, Clone)] 19 | pub struct Timeout { 20 | inner: T, 21 | timeout: Duration, 22 | } 23 | 24 | // ===== impl Timeout ===== 25 | 26 | impl Timeout { 27 | /// Creates a new [`Timeout`] 28 | pub const fn new(inner: T, timeout: Duration) -> Self { 29 | Timeout { inner, timeout } 30 | } 31 | 32 | /// Get a reference to the inner service 33 | pub fn get_ref(&self) -> &T { 34 | &self.inner 35 | } 36 | 37 | /// Get a mutable reference to the inner service 38 | pub fn get_mut(&mut self) -> &mut T { 39 | &mut self.inner 40 | } 41 | 42 | /// Consume `self`, returning the inner service 43 | pub fn into_inner(self) -> T { 44 | self.inner 45 | } 46 | } 47 | 48 | impl Service for Timeout 49 | where 50 | S: Service, 51 | S::Error: Into, 52 | { 53 | type Response = S::Response; 54 | type Error = crate::BoxError; 55 | type Future = ResponseFuture; 56 | 57 | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { 58 | match self.inner.poll_ready(cx) { 59 | Poll::Pending => Poll::Pending, 60 | Poll::Ready(r) => Poll::Ready(r.map_err(Into::into)), 61 | } 62 | } 63 | 64 | fn call(&mut self, request: Request) -> Self::Future { 65 | let response = self.inner.call(request); 66 | let sleep = tokio::time::sleep(self.timeout); 67 | 68 | ResponseFuture::new(response, sleep) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /tower/src/util/and_then.rs: -------------------------------------------------------------------------------- 1 | use futures_core::TryFuture; 2 | use futures_util::{future, TryFutureExt}; 3 | use std::fmt; 4 | use std::future::Future; 5 | use std::pin::Pin; 6 | use std::task::{Context, Poll}; 7 | use tower_layer::Layer; 8 | use tower_service::Service; 9 | 10 | /// Service returned by the [`and_then`] combinator. 11 | /// 12 | /// [`and_then`]: crate::util::ServiceExt::and_then 13 | #[derive(Clone)] 14 | pub struct AndThen { 15 | inner: S, 16 | f: F, 17 | } 18 | 19 | impl fmt::Debug for AndThen 20 | where 21 | S: fmt::Debug, 22 | { 23 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 24 | f.debug_struct("AndThen") 25 | .field("inner", &self.inner) 26 | .field("f", &format_args!("{}", std::any::type_name::())) 27 | .finish() 28 | } 29 | } 30 | 31 | pin_project_lite::pin_project! { 32 | /// Response future from [`AndThen`] services. 33 | /// 34 | /// [`AndThen`]: crate::util::AndThen 35 | pub struct AndThenFuture { 36 | #[pin] 37 | inner: future::AndThen, F2, N>, 38 | } 39 | } 40 | 41 | impl AndThenFuture { 42 | pub(crate) fn new(inner: future::AndThen, F2, N>) -> Self { 43 | Self { inner } 44 | } 45 | } 46 | 47 | impl std::fmt::Debug for AndThenFuture { 48 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 49 | f.debug_tuple("AndThenFuture") 50 | .field(&format_args!("...")) 51 | .finish() 52 | } 53 | } 54 | 55 | impl Future for AndThenFuture 56 | where 57 | future::AndThen, F2, N>: Future, 58 | { 59 | type Output = , F2, N> as Future>::Output; 60 | 61 | #[inline] 62 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 63 | self.project().inner.poll(cx) 64 | } 65 | } 66 | 67 | /// A [`Layer`] that produces a [`AndThen`] service. 68 | /// 69 | /// [`Layer`]: tower_layer::Layer 70 | #[derive(Clone, Debug)] 71 | pub struct AndThenLayer { 72 | f: F, 73 | } 74 | 75 | impl AndThen { 76 | /// Creates a new `AndThen` service. 77 | pub const fn new(inner: S, f: F) -> Self { 78 | AndThen { f, inner } 79 | } 80 | 81 | /// Returns a new [`Layer`] that produces [`AndThen`] services. 82 | /// 83 | /// This is a convenience function that simply calls [`AndThenLayer::new`]. 84 | /// 85 | /// [`Layer`]: tower_layer::Layer 86 | pub fn layer(f: F) -> AndThenLayer { 87 | AndThenLayer { f } 88 | } 89 | } 90 | 91 | impl Service for AndThen 92 | where 93 | S: Service, 94 | S::Error: Into, 95 | F: FnOnce(S::Response) -> Fut + Clone, 96 | Fut: TryFuture, 97 | { 98 | type Response = Fut::Ok; 99 | type Error = Fut::Error; 100 | type Future = AndThenFuture; 101 | 102 | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { 103 | self.inner.poll_ready(cx).map_err(Into::into) 104 | } 105 | 106 | fn call(&mut self, request: Request) -> Self::Future { 107 | AndThenFuture::new(self.inner.call(request).err_into().and_then(self.f.clone())) 108 | } 109 | } 110 | 111 | impl AndThenLayer { 112 | /// Creates a new [`AndThenLayer`] layer. 113 | pub const fn new(f: F) -> Self { 114 | AndThenLayer { f } 115 | } 116 | } 117 | 118 | impl Layer for AndThenLayer 119 | where 120 | F: Clone, 121 | { 122 | type Service = AndThen; 123 | 124 | fn layer(&self, inner: S) -> Self::Service { 125 | AndThen { 126 | f: self.f.clone(), 127 | inner, 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /tower/src/util/boxed/layer.rs: -------------------------------------------------------------------------------- 1 | use crate::util::BoxService; 2 | use std::{fmt, sync::Arc}; 3 | use tower_layer::{layer_fn, Layer}; 4 | use tower_service::Service; 5 | 6 | /// A boxed [`Layer`] trait object. 7 | /// 8 | /// [`BoxLayer`] turns a layer into a trait object, allowing both the [`Layer`] itself 9 | /// and the output [`Service`] to be dynamic, while having consistent types. 10 | /// 11 | /// This [`Layer`] produces [`BoxService`] instances erasing the type of the 12 | /// [`Service`] produced by the wrapped [`Layer`]. 13 | /// 14 | /// # Example 15 | /// 16 | /// `BoxLayer` can, for example, be useful to create layers dynamically that otherwise wouldn't have 17 | /// the same types. In this example, we include a [`Timeout`] layer 18 | /// only if an environment variable is set. We can use `BoxLayer` 19 | /// to return a consistent type regardless of runtime configuration: 20 | /// 21 | /// ``` 22 | /// use std::time::Duration; 23 | /// use tower::{Service, ServiceBuilder, BoxError, util::BoxLayer}; 24 | /// 25 | /// fn common_layer() -> BoxLayer 26 | /// where 27 | /// S: Service + Send + 'static, 28 | /// S::Future: Send + 'static, 29 | /// S::Error: Into + 'static, 30 | /// { 31 | /// let builder = ServiceBuilder::new() 32 | /// .concurrency_limit(100); 33 | /// 34 | /// if std::env::var("SET_TIMEOUT").is_ok() { 35 | /// let layer = builder 36 | /// .timeout(Duration::from_secs(30)) 37 | /// .into_inner(); 38 | /// 39 | /// BoxLayer::new(layer) 40 | /// } else { 41 | /// let layer = builder 42 | /// .map_err(Into::into) 43 | /// .into_inner(); 44 | /// 45 | /// BoxLayer::new(layer) 46 | /// } 47 | /// } 48 | /// ``` 49 | /// 50 | /// [`Layer`]: tower_layer::Layer 51 | /// [`Service`]: tower_service::Service 52 | /// [`BoxService`]: super::BoxService 53 | /// [`Timeout`]: crate::timeout 54 | pub struct BoxLayer { 55 | boxed: Arc> + Send + Sync + 'static>, 56 | } 57 | 58 | impl BoxLayer { 59 | /// Create a new [`BoxLayer`]. 60 | pub fn new(inner_layer: L) -> Self 61 | where 62 | L: Layer + Send + Sync + 'static, 63 | L::Service: Service + Send + 'static, 64 | >::Future: Send + 'static, 65 | { 66 | let layer = layer_fn(move |inner: In| { 67 | let out = inner_layer.layer(inner); 68 | BoxService::new(out) 69 | }); 70 | 71 | Self { 72 | boxed: Arc::new(layer), 73 | } 74 | } 75 | } 76 | 77 | impl Layer for BoxLayer { 78 | type Service = BoxService; 79 | 80 | fn layer(&self, inner: In) -> Self::Service { 81 | self.boxed.layer(inner) 82 | } 83 | } 84 | 85 | impl Clone for BoxLayer { 86 | fn clone(&self) -> Self { 87 | Self { 88 | boxed: Arc::clone(&self.boxed), 89 | } 90 | } 91 | } 92 | 93 | impl fmt::Debug for BoxLayer { 94 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 95 | fmt.debug_struct("BoxLayer").finish() 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /tower/src/util/boxed/mod.rs: -------------------------------------------------------------------------------- 1 | mod layer; 2 | mod layer_clone; 3 | mod layer_clone_sync; 4 | mod sync; 5 | mod unsync; 6 | 7 | #[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 8 | pub use self::{ 9 | layer::BoxLayer, layer_clone::BoxCloneServiceLayer, layer_clone_sync::BoxCloneSyncServiceLayer, 10 | sync::BoxService, unsync::UnsyncBoxService, 11 | }; 12 | -------------------------------------------------------------------------------- /tower/src/util/boxed/sync.rs: -------------------------------------------------------------------------------- 1 | use crate::ServiceExt; 2 | use tower_layer::{layer_fn, LayerFn}; 3 | use tower_service::Service; 4 | 5 | use sync_wrapper::SyncWrapper; 6 | 7 | use std::fmt; 8 | use std::{ 9 | future::Future, 10 | pin::Pin, 11 | task::{Context, Poll}, 12 | }; 13 | 14 | /// A boxed `Service + Send` trait object. 15 | /// 16 | /// [`BoxService`] turns a service into a trait object, allowing the response 17 | /// future type to be dynamic. This type requires both the service and the 18 | /// response future to be [`Send`]. 19 | /// 20 | /// If you need a boxed [`Service`] that implements [`Clone`] consider using 21 | /// [`BoxCloneService`](crate::util::BoxCloneService). 22 | /// 23 | /// Dynamically dispatched [`Service`] objects allow for erasing the underlying 24 | /// [`Service`] type and using the `Service` instances as opaque handles. This can 25 | /// be useful when the service instance cannot be explicitly named for whatever 26 | /// reason. 27 | /// 28 | /// # Examples 29 | /// 30 | /// ``` 31 | /// use std::future::ready; 32 | /// # use tower_service::Service; 33 | /// # use tower::util::{BoxService, service_fn}; 34 | /// // Respond to requests using a closure, but closures cannot be named... 35 | /// # pub fn main() { 36 | /// let svc = service_fn(|mut request: String| { 37 | /// request.push_str(" response"); 38 | /// ready(Ok(request)) 39 | /// }); 40 | /// 41 | /// let service: BoxService = BoxService::new(svc); 42 | /// # drop(service); 43 | /// } 44 | /// ``` 45 | /// 46 | /// [`Service`]: crate::Service 47 | /// [`Rc`]: std::rc::Rc 48 | pub struct BoxService { 49 | inner: 50 | SyncWrapper> + Send>>, 51 | } 52 | 53 | /// A boxed `Future + Send` trait object. 54 | /// 55 | /// This type alias represents a boxed future that is [`Send`] and can be moved 56 | /// across threads. 57 | type BoxFuture = Pin> + Send>>; 58 | 59 | impl BoxService { 60 | #[allow(missing_docs)] 61 | pub fn new(inner: S) -> Self 62 | where 63 | S: Service + Send + 'static, 64 | S::Future: Send + 'static, 65 | { 66 | // rust can't infer the type 67 | let inner: Box> + Send> = 68 | Box::new(inner.map_future(|f: S::Future| Box::pin(f) as _)); 69 | let inner = SyncWrapper::new(inner); 70 | BoxService { inner } 71 | } 72 | 73 | /// Returns a [`Layer`] for wrapping a [`Service`] in a [`BoxService`] 74 | /// middleware. 75 | /// 76 | /// [`Layer`]: crate::Layer 77 | pub fn layer() -> LayerFn Self> 78 | where 79 | S: Service + Send + 'static, 80 | S::Future: Send + 'static, 81 | { 82 | layer_fn(Self::new) 83 | } 84 | } 85 | 86 | impl Service for BoxService { 87 | type Response = U; 88 | type Error = E; 89 | type Future = BoxFuture; 90 | 91 | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { 92 | self.inner.get_mut().poll_ready(cx) 93 | } 94 | 95 | fn call(&mut self, request: T) -> BoxFuture { 96 | self.inner.get_mut().call(request) 97 | } 98 | } 99 | 100 | impl fmt::Debug for BoxService { 101 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 102 | fmt.debug_struct("BoxService").finish() 103 | } 104 | } 105 | 106 | #[test] 107 | fn is_sync() { 108 | fn assert_sync() {} 109 | 110 | assert_sync::>(); 111 | } 112 | -------------------------------------------------------------------------------- /tower/src/util/boxed/unsync.rs: -------------------------------------------------------------------------------- 1 | use tower_layer::{layer_fn, LayerFn}; 2 | use tower_service::Service; 3 | 4 | use std::fmt; 5 | use std::{ 6 | future::Future, 7 | pin::Pin, 8 | task::{Context, Poll}, 9 | }; 10 | 11 | /// A boxed [`Service`] trait object. 12 | pub struct UnsyncBoxService { 13 | inner: Box>>, 14 | } 15 | 16 | /// A boxed [`Future`] trait object. 17 | /// 18 | /// This type alias represents a boxed future that is *not* [`Send`] and must 19 | /// remain on the current thread. 20 | type UnsyncBoxFuture = Pin>>>; 21 | 22 | #[derive(Debug)] 23 | struct UnsyncBoxed { 24 | inner: S, 25 | } 26 | 27 | impl UnsyncBoxService { 28 | #[allow(missing_docs)] 29 | pub fn new(inner: S) -> Self 30 | where 31 | S: Service + 'static, 32 | S::Future: 'static, 33 | { 34 | let inner = Box::new(UnsyncBoxed { inner }); 35 | UnsyncBoxService { inner } 36 | } 37 | 38 | /// Returns a [`Layer`] for wrapping a [`Service`] in an [`UnsyncBoxService`] middleware. 39 | /// 40 | /// [`Layer`]: crate::Layer 41 | pub fn layer() -> LayerFn Self> 42 | where 43 | S: Service + 'static, 44 | S::Future: 'static, 45 | { 46 | layer_fn(Self::new) 47 | } 48 | } 49 | 50 | impl Service for UnsyncBoxService { 51 | type Response = U; 52 | type Error = E; 53 | type Future = UnsyncBoxFuture; 54 | 55 | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { 56 | self.inner.poll_ready(cx) 57 | } 58 | 59 | fn call(&mut self, request: T) -> UnsyncBoxFuture { 60 | self.inner.call(request) 61 | } 62 | } 63 | 64 | impl fmt::Debug for UnsyncBoxService { 65 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 66 | fmt.debug_struct("UnsyncBoxService").finish() 67 | } 68 | } 69 | 70 | impl Service for UnsyncBoxed 71 | where 72 | S: Service + 'static, 73 | S::Future: 'static, 74 | { 75 | type Response = S::Response; 76 | type Error = S::Error; 77 | type Future = Pin>>>; 78 | 79 | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { 80 | self.inner.poll_ready(cx) 81 | } 82 | 83 | fn call(&mut self, request: Request) -> Self::Future { 84 | Box::pin(self.inner.call(request)) 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /tower/src/util/boxed_clone_sync.rs: -------------------------------------------------------------------------------- 1 | use super::ServiceExt; 2 | use futures_util::future::BoxFuture; 3 | use std::{ 4 | fmt, 5 | task::{Context, Poll}, 6 | }; 7 | use tower_layer::{layer_fn, LayerFn}; 8 | use tower_service::Service; 9 | 10 | /// A [`Clone`] + [`Send`] + [`Sync`] boxed [`Service`]. 11 | /// 12 | /// [`BoxCloneSyncService`] turns a service into a trait object, allowing the 13 | /// response future type to be dynamic, and allowing the service to be cloned and shared. 14 | /// 15 | /// This is similar to [`BoxCloneService`](super::BoxCloneService) except the resulting 16 | /// service implements [`Sync`]. 17 | /// ``` 18 | pub struct BoxCloneSyncService( 19 | Box< 20 | dyn CloneService>> 21 | + Send 22 | + Sync, 23 | >, 24 | ); 25 | 26 | impl BoxCloneSyncService { 27 | /// Create a new `BoxCloneSyncService`. 28 | pub fn new(inner: S) -> Self 29 | where 30 | S: Service + Clone + Send + Sync + 'static, 31 | S::Future: Send + 'static, 32 | { 33 | let inner = inner.map_future(|f| Box::pin(f) as _); 34 | BoxCloneSyncService(Box::new(inner)) 35 | } 36 | 37 | /// Returns a [`Layer`] for wrapping a [`Service`] in a [`BoxCloneSyncService`] 38 | /// middleware. 39 | /// 40 | /// [`Layer`]: crate::Layer 41 | pub fn layer() -> LayerFn Self> 42 | where 43 | S: Service + Clone + Send + Sync + 'static, 44 | S::Future: Send + 'static, 45 | { 46 | layer_fn(Self::new) 47 | } 48 | } 49 | 50 | impl Service for BoxCloneSyncService { 51 | type Response = U; 52 | type Error = E; 53 | type Future = BoxFuture<'static, Result>; 54 | 55 | #[inline] 56 | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { 57 | self.0.poll_ready(cx) 58 | } 59 | 60 | #[inline] 61 | fn call(&mut self, request: T) -> Self::Future { 62 | self.0.call(request) 63 | } 64 | } 65 | 66 | impl Clone for BoxCloneSyncService { 67 | fn clone(&self) -> Self { 68 | Self(self.0.clone_box()) 69 | } 70 | } 71 | 72 | trait CloneService: Service { 73 | fn clone_box( 74 | &self, 75 | ) -> Box< 76 | dyn CloneService 77 | + Send 78 | + Sync, 79 | >; 80 | } 81 | 82 | impl CloneService for T 83 | where 84 | T: Service + Send + Sync + Clone + 'static, 85 | { 86 | fn clone_box( 87 | &self, 88 | ) -> Box< 89 | dyn CloneService 90 | + Send 91 | + Sync, 92 | > { 93 | Box::new(self.clone()) 94 | } 95 | } 96 | 97 | impl fmt::Debug for BoxCloneSyncService { 98 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 99 | fmt.debug_struct("BoxCloneSyncService").finish() 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /tower/src/util/call_all/mod.rs: -------------------------------------------------------------------------------- 1 | //! [`Stream`][stream] + [`Service`] => [`Stream`][stream]. 2 | //! 3 | //! [`Service`]: crate::Service 4 | //! [stream]: https://docs.rs/futures/latest/futures/stream/trait.Stream.html 5 | 6 | mod common; 7 | mod ordered; 8 | mod unordered; 9 | 10 | #[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411 11 | pub use self::{ordered::CallAll, unordered::CallAllUnordered}; 12 | -------------------------------------------------------------------------------- /tower/src/util/call_all/unordered.rs: -------------------------------------------------------------------------------- 1 | //! [`Stream`][stream] + [`Service`] => [`Stream`][stream]. 2 | //! 3 | //! [`Service`]: crate::Service 4 | //! [stream]: https://docs.rs/futures/latest/futures/stream/trait.Stream.html 5 | 6 | use super::common; 7 | use futures_core::Stream; 8 | use futures_util::stream::FuturesUnordered; 9 | use pin_project_lite::pin_project; 10 | use std::{ 11 | future::Future, 12 | pin::Pin, 13 | task::{Context, Poll}, 14 | }; 15 | use tower_service::Service; 16 | 17 | pin_project! { 18 | /// A stream of responses received from the inner service in received order. 19 | /// 20 | /// Similar to [`CallAll`] except, instead of yielding responses in request order, 21 | /// responses are returned as they are available. 22 | /// 23 | /// [`CallAll`]: crate::util::CallAll 24 | #[derive(Debug)] 25 | pub struct CallAllUnordered 26 | where 27 | Svc: Service, 28 | S: Stream, 29 | { 30 | #[pin] 31 | inner: common::CallAll>, 32 | } 33 | } 34 | 35 | impl CallAllUnordered 36 | where 37 | Svc: Service, 38 | S: Stream, 39 | { 40 | /// Create new [`CallAllUnordered`] combinator. 41 | /// 42 | /// [`Stream`]: https://docs.rs/futures/latest/futures/stream/trait.Stream.html 43 | pub fn new(service: Svc, stream: S) -> CallAllUnordered { 44 | CallAllUnordered { 45 | inner: common::CallAll::new(service, stream, FuturesUnordered::new()), 46 | } 47 | } 48 | 49 | /// Extract the wrapped [`Service`]. 50 | /// 51 | /// # Panics 52 | /// 53 | /// Panics if [`take_service`] was already called. 54 | /// 55 | /// [`take_service`]: crate::util::CallAllUnordered::take_service 56 | pub fn into_inner(self) -> Svc { 57 | self.inner.into_inner() 58 | } 59 | 60 | /// Extract the wrapped `Service`. 61 | /// 62 | /// This [`CallAllUnordered`] can no longer be used after this function has been called. 63 | /// 64 | /// # Panics 65 | /// 66 | /// Panics if [`take_service`] was already called. 67 | /// 68 | /// [`take_service`]: crate::util::CallAllUnordered::take_service 69 | pub fn take_service(self: Pin<&mut Self>) -> Svc { 70 | self.project().inner.take_service() 71 | } 72 | } 73 | 74 | impl Stream for CallAllUnordered 75 | where 76 | Svc: Service, 77 | S: Stream, 78 | { 79 | type Item = Result; 80 | 81 | fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { 82 | self.project().inner.poll_next(cx) 83 | } 84 | } 85 | 86 | impl common::Drive for FuturesUnordered { 87 | fn is_empty(&self) -> bool { 88 | FuturesUnordered::is_empty(self) 89 | } 90 | 91 | fn push(&mut self, future: F) { 92 | FuturesUnordered::push(self, future) 93 | } 94 | 95 | fn poll(&mut self, cx: &mut Context<'_>) -> Poll> { 96 | Stream::poll_next(Pin::new(self), cx) 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /tower/src/util/either.rs: -------------------------------------------------------------------------------- 1 | //! Contains [`Either`] and related types and functions. 2 | //! 3 | //! See [`Either`] documentation for more details. 4 | 5 | use pin_project_lite::pin_project; 6 | use std::{ 7 | future::Future, 8 | pin::Pin, 9 | task::{Context, Poll}, 10 | }; 11 | use tower_layer::Layer; 12 | use tower_service::Service; 13 | 14 | /// Combine two different service types into a single type. 15 | /// 16 | /// Both services must be of the same request, response, and error types. 17 | /// [`Either`] is useful for handling conditional branching in service middleware 18 | /// to different inner service types. 19 | #[derive(Clone, Copy, Debug)] 20 | pub enum Either { 21 | #[allow(missing_docs)] 22 | Left(A), 23 | #[allow(missing_docs)] 24 | Right(B), 25 | } 26 | 27 | impl Service for Either 28 | where 29 | A: Service, 30 | B: Service, 31 | { 32 | type Response = A::Response; 33 | type Error = A::Error; 34 | type Future = EitherResponseFuture; 35 | 36 | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { 37 | match self { 38 | Either::Left(service) => service.poll_ready(cx), 39 | Either::Right(service) => service.poll_ready(cx), 40 | } 41 | } 42 | 43 | fn call(&mut self, request: Request) -> Self::Future { 44 | match self { 45 | Either::Left(service) => EitherResponseFuture { 46 | kind: Kind::Left { 47 | inner: service.call(request), 48 | }, 49 | }, 50 | Either::Right(service) => EitherResponseFuture { 51 | kind: Kind::Right { 52 | inner: service.call(request), 53 | }, 54 | }, 55 | } 56 | } 57 | } 58 | 59 | pin_project! { 60 | /// Response future for [`Either`]. 61 | pub struct EitherResponseFuture { 62 | #[pin] 63 | kind: Kind 64 | } 65 | } 66 | 67 | pin_project! { 68 | #[project = KindProj] 69 | enum Kind { 70 | Left { #[pin] inner: A }, 71 | Right { #[pin] inner: B }, 72 | } 73 | } 74 | 75 | impl Future for EitherResponseFuture 76 | where 77 | A: Future, 78 | B: Future, 79 | { 80 | type Output = A::Output; 81 | 82 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 83 | match self.project().kind.project() { 84 | KindProj::Left { inner } => inner.poll(cx), 85 | KindProj::Right { inner } => inner.poll(cx), 86 | } 87 | } 88 | } 89 | 90 | impl Layer for Either 91 | where 92 | A: Layer, 93 | B: Layer, 94 | { 95 | type Service = Either; 96 | 97 | fn layer(&self, inner: S) -> Self::Service { 98 | match self { 99 | Either::Left(layer) => Either::Left(layer.layer(inner)), 100 | Either::Right(layer) => Either::Right(layer.layer(inner)), 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /tower/src/util/map_err.rs: -------------------------------------------------------------------------------- 1 | use futures_util::{future, TryFutureExt}; 2 | use std::fmt; 3 | use std::task::{Context, Poll}; 4 | use tower_layer::Layer; 5 | use tower_service::Service; 6 | 7 | /// Service returned by the [`map_err`] combinator. 8 | /// 9 | /// [`map_err`]: crate::util::ServiceExt::map_err 10 | #[derive(Clone)] 11 | pub struct MapErr { 12 | inner: S, 13 | f: F, 14 | } 15 | 16 | impl fmt::Debug for MapErr 17 | where 18 | S: fmt::Debug, 19 | { 20 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 21 | f.debug_struct("MapErr") 22 | .field("inner", &self.inner) 23 | .field("f", &format_args!("{}", std::any::type_name::())) 24 | .finish() 25 | } 26 | } 27 | 28 | /// A [`Layer`] that produces [`MapErr`] services. 29 | /// 30 | /// [`Layer`]: tower_layer::Layer 31 | #[derive(Clone, Debug)] 32 | pub struct MapErrLayer { 33 | f: F, 34 | } 35 | 36 | opaque_future! { 37 | /// Response future from [`MapErr`] services. 38 | /// 39 | /// [`MapErr`]: crate::util::MapErr 40 | pub type MapErrFuture = future::MapErr; 41 | } 42 | 43 | impl MapErr { 44 | /// Creates a new [`MapErr`] service. 45 | pub const fn new(inner: S, f: F) -> Self { 46 | MapErr { f, inner } 47 | } 48 | 49 | /// Returns a new [`Layer`] that produces [`MapErr`] services. 50 | /// 51 | /// This is a convenience function that simply calls [`MapErrLayer::new`]. 52 | /// 53 | /// [`Layer`]: tower_layer::Layer 54 | pub fn layer(f: F) -> MapErrLayer { 55 | MapErrLayer { f } 56 | } 57 | } 58 | 59 | impl Service for MapErr 60 | where 61 | S: Service, 62 | F: FnOnce(S::Error) -> Error + Clone, 63 | { 64 | type Response = S::Response; 65 | type Error = Error; 66 | type Future = MapErrFuture; 67 | 68 | #[inline] 69 | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { 70 | self.inner.poll_ready(cx).map_err(self.f.clone()) 71 | } 72 | 73 | #[inline] 74 | fn call(&mut self, request: Request) -> Self::Future { 75 | MapErrFuture::new(self.inner.call(request).map_err(self.f.clone())) 76 | } 77 | } 78 | 79 | impl MapErrLayer { 80 | /// Creates a new [`MapErrLayer`]. 81 | pub const fn new(f: F) -> Self { 82 | MapErrLayer { f } 83 | } 84 | } 85 | 86 | impl Layer for MapErrLayer 87 | where 88 | F: Clone, 89 | { 90 | type Service = MapErr; 91 | 92 | fn layer(&self, inner: S) -> Self::Service { 93 | MapErr { 94 | f: self.f.clone(), 95 | inner, 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /tower/src/util/map_future.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | fmt, 3 | future::Future, 4 | task::{Context, Poll}, 5 | }; 6 | use tower_layer::Layer; 7 | use tower_service::Service; 8 | 9 | /// [`Service`] returned by the [`map_future`] combinator. 10 | /// 11 | /// [`map_future`]: crate::util::ServiceExt::map_future 12 | #[derive(Clone)] 13 | pub struct MapFuture { 14 | inner: S, 15 | f: F, 16 | } 17 | 18 | impl MapFuture { 19 | /// Creates a new [`MapFuture`] service. 20 | pub const fn new(inner: S, f: F) -> Self { 21 | Self { inner, f } 22 | } 23 | 24 | /// Returns a new [`Layer`] that produces [`MapFuture`] services. 25 | /// 26 | /// This is a convenience function that simply calls [`MapFutureLayer::new`]. 27 | /// 28 | /// [`Layer`]: tower_layer::Layer 29 | pub fn layer(f: F) -> MapFutureLayer { 30 | MapFutureLayer::new(f) 31 | } 32 | 33 | /// Get a reference to the inner service 34 | pub fn get_ref(&self) -> &S { 35 | &self.inner 36 | } 37 | 38 | /// Get a mutable reference to the inner service 39 | pub fn get_mut(&mut self) -> &mut S { 40 | &mut self.inner 41 | } 42 | 43 | /// Consume `self`, returning the inner service 44 | pub fn into_inner(self) -> S { 45 | self.inner 46 | } 47 | } 48 | 49 | impl Service for MapFuture 50 | where 51 | S: Service, 52 | F: FnMut(S::Future) -> Fut, 53 | E: From, 54 | Fut: Future>, 55 | { 56 | type Response = T; 57 | type Error = E; 58 | type Future = Fut; 59 | 60 | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { 61 | self.inner.poll_ready(cx).map_err(From::from) 62 | } 63 | 64 | fn call(&mut self, req: R) -> Self::Future { 65 | (self.f)(self.inner.call(req)) 66 | } 67 | } 68 | 69 | impl fmt::Debug for MapFuture 70 | where 71 | S: fmt::Debug, 72 | { 73 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 74 | f.debug_struct("MapFuture") 75 | .field("inner", &self.inner) 76 | .field("f", &format_args!("{}", std::any::type_name::())) 77 | .finish() 78 | } 79 | } 80 | 81 | /// A [`Layer`] that produces a [`MapFuture`] service. 82 | /// 83 | /// [`Layer`]: tower_layer::Layer 84 | #[derive(Clone)] 85 | pub struct MapFutureLayer { 86 | f: F, 87 | } 88 | 89 | impl MapFutureLayer { 90 | /// Creates a new [`MapFutureLayer`] layer. 91 | pub const fn new(f: F) -> Self { 92 | Self { f } 93 | } 94 | } 95 | 96 | impl Layer for MapFutureLayer 97 | where 98 | F: Clone, 99 | { 100 | type Service = MapFuture; 101 | 102 | fn layer(&self, inner: S) -> Self::Service { 103 | MapFuture::new(inner, self.f.clone()) 104 | } 105 | } 106 | 107 | impl fmt::Debug for MapFutureLayer { 108 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 109 | f.debug_struct("MapFutureLayer") 110 | .field("f", &format_args!("{}", std::any::type_name::())) 111 | .finish() 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /tower/src/util/map_request.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::task::{Context, Poll}; 3 | use tower_layer::Layer; 4 | use tower_service::Service; 5 | 6 | /// Service returned by the [`MapRequest`] combinator. 7 | /// 8 | /// [`MapRequest`]: crate::util::ServiceExt::map_request 9 | #[derive(Clone)] 10 | pub struct MapRequest { 11 | inner: S, 12 | f: F, 13 | } 14 | 15 | impl fmt::Debug for MapRequest 16 | where 17 | S: fmt::Debug, 18 | { 19 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 20 | f.debug_struct("MapRequest") 21 | .field("inner", &self.inner) 22 | .field("f", &format_args!("{}", std::any::type_name::())) 23 | .finish() 24 | } 25 | } 26 | 27 | impl MapRequest { 28 | /// Creates a new [`MapRequest`] service. 29 | pub const fn new(inner: S, f: F) -> Self { 30 | MapRequest { inner, f } 31 | } 32 | 33 | /// Returns a new [`Layer`] that produces [`MapRequest`] services. 34 | /// 35 | /// This is a convenience function that simply calls [`MapRequestLayer::new`]. 36 | /// 37 | /// [`Layer`]: tower_layer::Layer 38 | pub fn layer(f: F) -> MapRequestLayer { 39 | MapRequestLayer { f } 40 | } 41 | } 42 | 43 | impl Service for MapRequest 44 | where 45 | S: Service, 46 | F: FnMut(R1) -> R2, 47 | { 48 | type Response = S::Response; 49 | type Error = S::Error; 50 | type Future = S::Future; 51 | 52 | #[inline] 53 | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { 54 | self.inner.poll_ready(cx) 55 | } 56 | 57 | #[inline] 58 | fn call(&mut self, request: R1) -> S::Future { 59 | self.inner.call((self.f)(request)) 60 | } 61 | } 62 | 63 | /// A [`Layer`] that produces [`MapRequest`] services. 64 | /// 65 | /// [`Layer`]: tower_layer::Layer 66 | #[derive(Clone, Debug)] 67 | pub struct MapRequestLayer { 68 | f: F, 69 | } 70 | 71 | impl MapRequestLayer { 72 | /// Creates a new [`MapRequestLayer`]. 73 | pub const fn new(f: F) -> Self { 74 | MapRequestLayer { f } 75 | } 76 | } 77 | 78 | impl Layer for MapRequestLayer 79 | where 80 | F: Clone, 81 | { 82 | type Service = MapRequest; 83 | 84 | fn layer(&self, inner: S) -> Self::Service { 85 | MapRequest { 86 | f: self.f.clone(), 87 | inner, 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /tower/src/util/map_response.rs: -------------------------------------------------------------------------------- 1 | use futures_util::{future::MapOk, TryFutureExt}; 2 | use std::fmt; 3 | use std::task::{Context, Poll}; 4 | use tower_layer::Layer; 5 | use tower_service::Service; 6 | 7 | /// Service returned by the [`map_response`] combinator. 8 | /// 9 | /// [`map_response`]: crate::util::ServiceExt::map_response 10 | #[derive(Clone)] 11 | pub struct MapResponse { 12 | inner: S, 13 | f: F, 14 | } 15 | 16 | impl fmt::Debug for MapResponse 17 | where 18 | S: fmt::Debug, 19 | { 20 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 21 | f.debug_struct("MapResponse") 22 | .field("inner", &self.inner) 23 | .field("f", &format_args!("{}", std::any::type_name::())) 24 | .finish() 25 | } 26 | } 27 | 28 | /// A [`Layer`] that produces a [`MapResponse`] service. 29 | /// 30 | /// [`Layer`]: tower_layer::Layer 31 | #[derive(Debug, Clone)] 32 | pub struct MapResponseLayer { 33 | f: F, 34 | } 35 | 36 | opaque_future! { 37 | /// Response future from [`MapResponse`] services. 38 | /// 39 | /// [`MapResponse`]: crate::util::MapResponse 40 | pub type MapResponseFuture = MapOk; 41 | } 42 | 43 | impl MapResponse { 44 | /// Creates a new `MapResponse` service. 45 | pub const fn new(inner: S, f: F) -> Self { 46 | MapResponse { f, inner } 47 | } 48 | 49 | /// Returns a new [`Layer`] that produces [`MapResponse`] services. 50 | /// 51 | /// This is a convenience function that simply calls [`MapResponseLayer::new`]. 52 | /// 53 | /// [`Layer`]: tower_layer::Layer 54 | pub fn layer(f: F) -> MapResponseLayer { 55 | MapResponseLayer { f } 56 | } 57 | } 58 | 59 | impl Service for MapResponse 60 | where 61 | S: Service, 62 | F: FnOnce(S::Response) -> Response + Clone, 63 | { 64 | type Response = Response; 65 | type Error = S::Error; 66 | type Future = MapResponseFuture; 67 | 68 | #[inline] 69 | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { 70 | self.inner.poll_ready(cx) 71 | } 72 | 73 | #[inline] 74 | fn call(&mut self, request: Request) -> Self::Future { 75 | MapResponseFuture::new(self.inner.call(request).map_ok(self.f.clone())) 76 | } 77 | } 78 | 79 | impl MapResponseLayer { 80 | /// Creates a new [`MapResponseLayer`] layer. 81 | pub const fn new(f: F) -> Self { 82 | MapResponseLayer { f } 83 | } 84 | } 85 | 86 | impl Layer for MapResponseLayer 87 | where 88 | F: Clone, 89 | { 90 | type Service = MapResponse; 91 | 92 | fn layer(&self, inner: S) -> Self::Service { 93 | MapResponse { 94 | f: self.f.clone(), 95 | inner, 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /tower/src/util/map_result.rs: -------------------------------------------------------------------------------- 1 | use futures_util::{future::Map, FutureExt}; 2 | use std::fmt; 3 | use std::task::{Context, Poll}; 4 | use tower_layer::Layer; 5 | use tower_service::Service; 6 | 7 | /// Service returned by the [`map_result`] combinator. 8 | /// 9 | /// [`map_result`]: crate::util::ServiceExt::map_result 10 | #[derive(Clone)] 11 | pub struct MapResult { 12 | inner: S, 13 | f: F, 14 | } 15 | 16 | impl fmt::Debug for MapResult 17 | where 18 | S: fmt::Debug, 19 | { 20 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 21 | f.debug_struct("MapResult") 22 | .field("inner", &self.inner) 23 | .field("f", &format_args!("{}", std::any::type_name::())) 24 | .finish() 25 | } 26 | } 27 | 28 | /// A [`Layer`] that produces a [`MapResult`] service. 29 | /// 30 | /// [`Layer`]: tower_layer::Layer 31 | #[derive(Debug, Clone)] 32 | pub struct MapResultLayer { 33 | f: F, 34 | } 35 | 36 | opaque_future! { 37 | /// Response future from [`MapResult`] services. 38 | /// 39 | /// [`MapResult`]: crate::util::MapResult 40 | pub type MapResultFuture = Map; 41 | } 42 | 43 | impl MapResult { 44 | /// Creates a new [`MapResult`] service. 45 | pub const fn new(inner: S, f: F) -> Self { 46 | MapResult { f, inner } 47 | } 48 | 49 | /// Returns a new [`Layer`] that produces [`MapResult`] services. 50 | /// 51 | /// This is a convenience function that simply calls [`MapResultLayer::new`]. 52 | /// 53 | /// [`Layer`]: tower_layer::Layer 54 | pub fn layer(f: F) -> MapResultLayer { 55 | MapResultLayer { f } 56 | } 57 | } 58 | 59 | impl Service for MapResult 60 | where 61 | S: Service, 62 | Error: From, 63 | F: FnOnce(Result) -> Result + Clone, 64 | { 65 | type Response = Response; 66 | type Error = Error; 67 | type Future = MapResultFuture; 68 | 69 | #[inline] 70 | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { 71 | self.inner.poll_ready(cx).map_err(Into::into) 72 | } 73 | 74 | #[inline] 75 | fn call(&mut self, request: Request) -> Self::Future { 76 | MapResultFuture::new(self.inner.call(request).map(self.f.clone())) 77 | } 78 | } 79 | 80 | impl MapResultLayer { 81 | /// Creates a new [`MapResultLayer`] layer. 82 | pub const fn new(f: F) -> Self { 83 | MapResultLayer { f } 84 | } 85 | } 86 | 87 | impl Layer for MapResultLayer 88 | where 89 | F: Clone, 90 | { 91 | type Service = MapResult; 92 | 93 | fn layer(&self, inner: S) -> Self::Service { 94 | MapResult { 95 | f: self.f.clone(), 96 | inner, 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /tower/src/util/oneshot.rs: -------------------------------------------------------------------------------- 1 | use pin_project_lite::pin_project; 2 | use std::{ 3 | fmt, 4 | future::Future, 5 | pin::Pin, 6 | task::{ready, Context, Poll}, 7 | }; 8 | use tower_service::Service; 9 | 10 | pin_project! { 11 | /// A [`Future`] consuming a [`Service`] and request, waiting until the [`Service`] 12 | /// is ready, and then calling [`Service::call`] with the request, and 13 | /// waiting for that [`Future`]. 14 | #[derive(Debug)] 15 | pub struct Oneshot, Req> { 16 | #[pin] 17 | state: State, 18 | } 19 | } 20 | 21 | pin_project! { 22 | #[project = StateProj] 23 | enum State, Req> { 24 | NotReady { 25 | svc: S, 26 | req: Option, 27 | }, 28 | Called { 29 | #[pin] 30 | fut: S::Future, 31 | }, 32 | Done, 33 | } 34 | } 35 | 36 | impl, Req> State { 37 | const fn not_ready(svc: S, req: Option) -> Self { 38 | Self::NotReady { svc, req } 39 | } 40 | 41 | const fn called(fut: S::Future) -> Self { 42 | Self::Called { fut } 43 | } 44 | } 45 | 46 | impl fmt::Debug for State 47 | where 48 | S: Service + fmt::Debug, 49 | Req: fmt::Debug, 50 | { 51 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 52 | match self { 53 | State::NotReady { 54 | svc, 55 | req: Some(req), 56 | } => f 57 | .debug_tuple("State::NotReady") 58 | .field(svc) 59 | .field(req) 60 | .finish(), 61 | State::NotReady { req: None, .. } => unreachable!(), 62 | State::Called { .. } => f.debug_tuple("State::Called").field(&"S::Future").finish(), 63 | State::Done => f.debug_tuple("State::Done").finish(), 64 | } 65 | } 66 | } 67 | 68 | impl Oneshot 69 | where 70 | S: Service, 71 | { 72 | #[allow(missing_docs)] 73 | pub const fn new(svc: S, req: Req) -> Self { 74 | Oneshot { 75 | state: State::not_ready(svc, Some(req)), 76 | } 77 | } 78 | } 79 | 80 | impl Future for Oneshot 81 | where 82 | S: Service, 83 | { 84 | type Output = Result; 85 | 86 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 87 | let mut this = self.project(); 88 | loop { 89 | match this.state.as_mut().project() { 90 | StateProj::NotReady { svc, req } => { 91 | let _ = ready!(svc.poll_ready(cx))?; 92 | let f = svc.call(req.take().expect("already called")); 93 | this.state.set(State::called(f)); 94 | } 95 | StateProj::Called { fut } => { 96 | let res = ready!(fut.poll(cx))?; 97 | this.state.set(State::Done); 98 | return Poll::Ready(Ok(res)); 99 | } 100 | StateProj::Done => panic!("polled after complete"), 101 | } 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /tower/src/util/optional/error.rs: -------------------------------------------------------------------------------- 1 | use std::{error, fmt}; 2 | 3 | /// Error returned if the inner [`Service`] has not been set. 4 | /// 5 | /// [`Service`]: crate::Service 6 | #[derive(Debug)] 7 | pub struct None(()); 8 | 9 | impl None { 10 | pub(crate) fn new() -> None { 11 | None(()) 12 | } 13 | } 14 | 15 | impl fmt::Display for None { 16 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 17 | write!(fmt, "None") 18 | } 19 | } 20 | 21 | impl error::Error for None {} 22 | -------------------------------------------------------------------------------- /tower/src/util/optional/future.rs: -------------------------------------------------------------------------------- 1 | use super::error; 2 | use pin_project_lite::pin_project; 3 | use std::{ 4 | future::Future, 5 | pin::Pin, 6 | task::{ready, Context, Poll}, 7 | }; 8 | 9 | pin_project! { 10 | /// Response future returned by [`Optional`]. 11 | /// 12 | /// [`Optional`]: crate::util::Optional 13 | #[derive(Debug)] 14 | pub struct ResponseFuture { 15 | #[pin] 16 | inner: Option, 17 | } 18 | } 19 | 20 | impl ResponseFuture { 21 | pub(crate) fn new(inner: Option) -> ResponseFuture { 22 | ResponseFuture { inner } 23 | } 24 | } 25 | 26 | impl Future for ResponseFuture 27 | where 28 | F: Future>, 29 | E: Into, 30 | { 31 | type Output = Result; 32 | 33 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 34 | match self.project().inner.as_pin_mut() { 35 | Some(inner) => Poll::Ready(Ok(ready!(inner.poll(cx)).map_err(Into::into)?)), 36 | None => Poll::Ready(Err(error::None::new().into())), 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tower/src/util/optional/mod.rs: -------------------------------------------------------------------------------- 1 | //! Contains [`Optional`] and related types and functions. 2 | //! 3 | //! See [`Optional`] documentation for more details. 4 | 5 | /// Error types for [`Optional`]. 6 | pub mod error; 7 | /// Future types for [`Optional`]. 8 | pub mod future; 9 | 10 | use self::future::ResponseFuture; 11 | use std::task::{Context, Poll}; 12 | use tower_service::Service; 13 | 14 | /// Optionally forwards requests to an inner service. 15 | /// 16 | /// If the inner service is [`None`], [`optional::None`] is returned as the response. 17 | /// 18 | /// [`optional::None`]: crate::util::error::optional::None 19 | #[derive(Debug)] 20 | pub struct Optional { 21 | inner: Option, 22 | } 23 | 24 | impl Optional { 25 | /// Create a new [`Optional`]. 26 | pub const fn new(inner: Option) -> Optional 27 | where 28 | T: Service, 29 | T::Error: Into, 30 | { 31 | Optional { inner } 32 | } 33 | } 34 | 35 | impl Service for Optional 36 | where 37 | T: Service, 38 | T::Error: Into, 39 | { 40 | type Response = T::Response; 41 | type Error = crate::BoxError; 42 | type Future = ResponseFuture; 43 | 44 | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { 45 | match self.inner { 46 | Some(ref mut inner) => match inner.poll_ready(cx) { 47 | Poll::Ready(r) => Poll::Ready(r.map_err(Into::into)), 48 | Poll::Pending => Poll::Pending, 49 | }, 50 | // None services are always ready 51 | None => Poll::Ready(Ok(())), 52 | } 53 | } 54 | 55 | fn call(&mut self, request: Request) -> Self::Future { 56 | let inner = self.inner.as_mut().map(|i| i.call(request)); 57 | ResponseFuture::new(inner) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /tower/src/util/ready.rs: -------------------------------------------------------------------------------- 1 | use std::{fmt, marker::PhantomData}; 2 | 3 | use std::{ 4 | future::Future, 5 | pin::Pin, 6 | task::{ready, Context, Poll}, 7 | }; 8 | use tower_service::Service; 9 | 10 | /// A [`Future`] that yields the service when it is ready to accept a request. 11 | /// 12 | /// [`ReadyOneshot`] values are produced by [`ServiceExt::ready_oneshot`]. 13 | /// 14 | /// [`ServiceExt::ready_oneshot`]: crate::util::ServiceExt::ready_oneshot 15 | pub struct ReadyOneshot { 16 | inner: Option, 17 | _p: PhantomData Request>, 18 | } 19 | 20 | // Safety: This is safe because `Services`'s are always `Unpin`. 21 | impl Unpin for ReadyOneshot {} 22 | 23 | impl ReadyOneshot 24 | where 25 | T: Service, 26 | { 27 | #[allow(missing_docs)] 28 | pub const fn new(service: T) -> Self { 29 | Self { 30 | inner: Some(service), 31 | _p: PhantomData, 32 | } 33 | } 34 | } 35 | 36 | impl Future for ReadyOneshot 37 | where 38 | T: Service, 39 | { 40 | type Output = Result; 41 | 42 | fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 43 | ready!(self 44 | .inner 45 | .as_mut() 46 | .expect("poll after Poll::Ready") 47 | .poll_ready(cx))?; 48 | 49 | Poll::Ready(Ok(self.inner.take().expect("poll after Poll::Ready"))) 50 | } 51 | } 52 | 53 | impl fmt::Debug for ReadyOneshot 54 | where 55 | T: fmt::Debug, 56 | { 57 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 58 | f.debug_struct("ReadyOneshot") 59 | .field("inner", &self.inner) 60 | .finish() 61 | } 62 | } 63 | 64 | /// A future that yields a mutable reference to the service when it is ready to accept a request. 65 | /// 66 | /// [`Ready`] values are produced by [`ServiceExt::ready`]. 67 | /// 68 | /// [`ServiceExt::ready`]: crate::util::ServiceExt::ready 69 | pub struct Ready<'a, T, Request>(ReadyOneshot<&'a mut T, Request>); 70 | 71 | // Safety: This is safe for the same reason that the impl for ReadyOneshot is safe. 72 | impl<'a, T, Request> Unpin for Ready<'a, T, Request> {} 73 | 74 | impl<'a, T, Request> Ready<'a, T, Request> 75 | where 76 | T: Service, 77 | { 78 | #[allow(missing_docs)] 79 | pub fn new(service: &'a mut T) -> Self { 80 | Self(ReadyOneshot::new(service)) 81 | } 82 | } 83 | 84 | impl<'a, T, Request> Future for Ready<'a, T, Request> 85 | where 86 | T: Service, 87 | { 88 | type Output = Result<&'a mut T, T::Error>; 89 | 90 | fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 91 | Pin::new(&mut self.0).poll(cx) 92 | } 93 | } 94 | 95 | impl<'a, T, Request> fmt::Debug for Ready<'a, T, Request> 96 | where 97 | T: fmt::Debug, 98 | { 99 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 100 | f.debug_tuple("Ready").field(&self.0).finish() 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /tower/src/util/service_fn.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::future::Future; 3 | use std::task::{Context, Poll}; 4 | use tower_service::Service; 5 | 6 | /// Returns a new [`ServiceFn`] with the given closure. 7 | /// 8 | /// This lets you build a [`Service`] from an async function that returns a [`Result`]. 9 | /// 10 | /// # Example 11 | /// 12 | /// ``` 13 | /// use tower::{service_fn, Service, ServiceExt, BoxError}; 14 | /// # struct Request; 15 | /// # impl Request { 16 | /// # fn new() -> Self { Self } 17 | /// # } 18 | /// # struct Response(&'static str); 19 | /// # impl Response { 20 | /// # fn new(body: &'static str) -> Self { 21 | /// # Self(body) 22 | /// # } 23 | /// # fn into_body(self) -> &'static str { self.0 } 24 | /// # } 25 | /// 26 | /// # #[tokio::main] 27 | /// # async fn main() -> Result<(), BoxError> { 28 | /// async fn handle(request: Request) -> Result { 29 | /// let response = Response::new("Hello, World!"); 30 | /// Ok(response) 31 | /// } 32 | /// 33 | /// let mut service = service_fn(handle); 34 | /// 35 | /// let response = service 36 | /// .ready() 37 | /// .await? 38 | /// .call(Request::new()) 39 | /// .await?; 40 | /// 41 | /// assert_eq!("Hello, World!", response.into_body()); 42 | /// # 43 | /// # Ok(()) 44 | /// # } 45 | /// ``` 46 | pub fn service_fn(f: T) -> ServiceFn { 47 | ServiceFn { f } 48 | } 49 | 50 | /// A [`Service`] implemented by a closure. 51 | /// 52 | /// See [`service_fn`] for more details. 53 | #[derive(Copy, Clone)] 54 | pub struct ServiceFn { 55 | f: T, 56 | } 57 | 58 | impl fmt::Debug for ServiceFn { 59 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 60 | f.debug_struct("ServiceFn") 61 | .field("f", &format_args!("{}", std::any::type_name::())) 62 | .finish() 63 | } 64 | } 65 | 66 | impl Service for ServiceFn 67 | where 68 | T: FnMut(Request) -> F, 69 | F: Future>, 70 | { 71 | type Response = R; 72 | type Error = E; 73 | type Future = F; 74 | 75 | fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll> { 76 | Ok(()).into() 77 | } 78 | 79 | fn call(&mut self, req: Request) -> Self::Future { 80 | (self.f)(req) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /tower/src/util/then.rs: -------------------------------------------------------------------------------- 1 | use futures_util::{future, FutureExt}; 2 | use std::{ 3 | fmt, 4 | future::Future, 5 | task::{Context, Poll}, 6 | }; 7 | use tower_layer::Layer; 8 | use tower_service::Service; 9 | 10 | /// [`Service`] returned by the [`then`] combinator. 11 | /// 12 | /// [`then`]: crate::util::ServiceExt::then 13 | #[derive(Clone)] 14 | pub struct Then { 15 | inner: S, 16 | f: F, 17 | } 18 | 19 | impl fmt::Debug for Then 20 | where 21 | S: fmt::Debug, 22 | { 23 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 24 | f.debug_struct("Then") 25 | .field("inner", &self.inner) 26 | .field("f", &format_args!("{}", std::any::type_name::())) 27 | .finish() 28 | } 29 | } 30 | 31 | /// A [`Layer`] that produces a [`Then`] service. 32 | /// 33 | /// [`Layer`]: tower_layer::Layer 34 | #[derive(Debug, Clone)] 35 | pub struct ThenLayer { 36 | f: F, 37 | } 38 | 39 | impl Then { 40 | /// Creates a new `Then` service. 41 | pub const fn new(inner: S, f: F) -> Self { 42 | Then { f, inner } 43 | } 44 | 45 | /// Returns a new [`Layer`] that produces [`Then`] services. 46 | /// 47 | /// This is a convenience function that simply calls [`ThenLayer::new`]. 48 | /// 49 | /// [`Layer`]: tower_layer::Layer 50 | pub fn layer(f: F) -> ThenLayer { 51 | ThenLayer { f } 52 | } 53 | } 54 | 55 | opaque_future! { 56 | /// Response future from [`Then`] services. 57 | /// 58 | /// [`Then`]: crate::util::Then 59 | pub type ThenFuture = future::Then; 60 | } 61 | 62 | impl Service for Then 63 | where 64 | S: Service, 65 | S::Error: Into, 66 | F: FnOnce(Result) -> Fut + Clone, 67 | Fut: Future>, 68 | { 69 | type Response = Response; 70 | type Error = Error; 71 | type Future = ThenFuture; 72 | 73 | #[inline] 74 | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { 75 | self.inner.poll_ready(cx).map_err(Into::into) 76 | } 77 | 78 | #[inline] 79 | fn call(&mut self, request: Request) -> Self::Future { 80 | ThenFuture::new(self.inner.call(request).then(self.f.clone())) 81 | } 82 | } 83 | 84 | impl ThenLayer { 85 | /// Creates a new [`ThenLayer`] layer. 86 | pub const fn new(f: F) -> Self { 87 | ThenLayer { f } 88 | } 89 | } 90 | 91 | impl Layer for ThenLayer 92 | where 93 | F: Clone, 94 | { 95 | type Service = Then; 96 | 97 | fn layer(&self, inner: S) -> Self::Service { 98 | Then { 99 | f: self.f.clone(), 100 | inner, 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /tower/tests/builder.rs: -------------------------------------------------------------------------------- 1 | #![cfg(all(feature = "buffer", feature = "limit", feature = "retry"))] 2 | mod support; 3 | use futures_util::pin_mut; 4 | use std::{future::Ready, time::Duration}; 5 | use tower::builder::ServiceBuilder; 6 | use tower::retry::Policy; 7 | use tower::util::ServiceExt; 8 | use tower_service::*; 9 | use tower_test::{assert_request_eq, mock}; 10 | 11 | #[tokio::test(flavor = "current_thread")] 12 | async fn builder_service() { 13 | let _t = support::trace_init(); 14 | 15 | let (service, handle) = mock::pair(); 16 | pin_mut!(handle); 17 | 18 | let policy = MockPolicy::<&'static str, bool>::default(); 19 | let mut client = ServiceBuilder::new() 20 | .buffer(5) 21 | .concurrency_limit(5) 22 | .rate_limit(5, Duration::from_secs(5)) 23 | .retry(policy) 24 | .map_response(|r: &'static str| r == "world") 25 | .map_request(|r: &'static str| r == "hello") 26 | .service(service); 27 | 28 | // allow a request through 29 | handle.allow(1); 30 | 31 | let fut = client.ready().await.unwrap().call("hello"); 32 | assert_request_eq!(handle, true).send_response("world"); 33 | assert!(fut.await.unwrap()); 34 | } 35 | 36 | #[derive(Debug, Clone, Default)] 37 | struct MockPolicy { 38 | _pd: std::marker::PhantomData<(Req, Res)>, 39 | } 40 | 41 | impl Policy for MockPolicy 42 | where 43 | Req: Clone, 44 | E: Into>, 45 | { 46 | type Future = Ready<()>; 47 | 48 | fn retry(&mut self, _req: &mut Req, _result: &mut Result) -> Option { 49 | None 50 | } 51 | 52 | fn clone_request(&mut self, req: &Req) -> Option { 53 | Some(req.clone()) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /tower/tests/filter/async_filter.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "filter")] 2 | #[path = "../support.rs"] 3 | mod support; 4 | use futures_util::future::pin_mut; 5 | use std::future::{poll_fn, Future}; 6 | use tower::filter::{error::Error, AsyncFilter}; 7 | use tower_service::Service; 8 | use tower_test::{assert_request_eq, mock}; 9 | 10 | #[tokio::test(flavor = "current_thread")] 11 | async fn passthrough_sync() { 12 | let _t = support::trace_init(); 13 | 14 | let (mut service, handle) = new_service(|_| async { Ok(()) }); 15 | 16 | let th = tokio::spawn(async move { 17 | // Receive the requests and respond 18 | pin_mut!(handle); 19 | for i in 0..10usize { 20 | assert_request_eq!(handle, format!("ping-{}", i)).send_response(format!("pong-{}", i)); 21 | } 22 | }); 23 | 24 | let mut responses = vec![]; 25 | 26 | for i in 0usize..10 { 27 | let request = format!("ping-{}", i); 28 | poll_fn(|cx| service.poll_ready(cx)).await.unwrap(); 29 | let exchange = service.call(request); 30 | let exchange = async move { 31 | let response = exchange.await.unwrap(); 32 | let expect = format!("pong-{}", i); 33 | assert_eq!(response.as_str(), expect.as_str()); 34 | }; 35 | 36 | responses.push(exchange); 37 | } 38 | 39 | futures_util::future::join_all(responses).await; 40 | th.await.unwrap(); 41 | } 42 | 43 | #[tokio::test(flavor = "current_thread")] 44 | async fn rejected_sync() { 45 | let _t = support::trace_init(); 46 | 47 | let (mut service, _handle) = new_service(|_| async { Err(Error::rejected()) }); 48 | 49 | service.call("hello".into()).await.unwrap_err(); 50 | } 51 | 52 | type Mock = mock::Mock; 53 | type Handle = mock::Handle; 54 | 55 | fn new_service(f: F) -> (AsyncFilter, Handle) 56 | where 57 | F: Fn(&String) -> U, 58 | U: Future>, 59 | { 60 | let (service, handle) = mock::pair(); 61 | let service = AsyncFilter::new(service, f); 62 | (service, handle) 63 | } 64 | -------------------------------------------------------------------------------- /tower/tests/limit/main.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "limit")] 2 | mod concurrency; 3 | mod rate; 4 | #[path = "../support.rs"] 5 | pub(crate) mod support; 6 | -------------------------------------------------------------------------------- /tower/tests/limit/rate.rs: -------------------------------------------------------------------------------- 1 | use super::support; 2 | use std::time::Duration; 3 | use tokio::time; 4 | use tokio_test::{assert_pending, assert_ready, assert_ready_ok}; 5 | use tower::limit::rate::RateLimitLayer; 6 | use tower_test::{assert_request_eq, mock}; 7 | 8 | #[tokio::test(flavor = "current_thread")] 9 | async fn reaching_capacity() { 10 | let _t = support::trace_init(); 11 | time::pause(); 12 | 13 | let rate_limit = RateLimitLayer::new(1, Duration::from_millis(100)); 14 | let (mut service, mut handle) = mock::spawn_layer(rate_limit); 15 | 16 | assert_ready_ok!(service.poll_ready()); 17 | 18 | let response = service.call("hello"); 19 | 20 | assert_request_eq!(handle, "hello").send_response("world"); 21 | 22 | assert_eq!(response.await.unwrap(), "world"); 23 | assert_pending!(service.poll_ready()); 24 | 25 | assert_pending!(handle.poll_request()); 26 | 27 | time::advance(Duration::from_millis(101)).await; 28 | 29 | assert_ready_ok!(service.poll_ready()); 30 | 31 | let response = service.call("two"); 32 | 33 | assert_request_eq!(handle, "two").send_response("done"); 34 | 35 | assert_eq!(response.await.unwrap(), "done"); 36 | } 37 | 38 | #[tokio::test(flavor = "current_thread")] 39 | async fn remaining_gets_reset() { 40 | // This test checks for the case where the `until` state gets reset 41 | // but the `rem` does not. This was a bug found `cd7dd12315706fc0860a35646b1eb7b60c50a5c1`. 42 | // 43 | // The main premise here is that we can make one request which should initialize the state 44 | // as ready. Then we can advance the clock to put us beyond the current period. When we make 45 | // subsequent requests the `rem` for the next window is continued from the previous when 46 | // it should be totally reset. 47 | let _t = support::trace_init(); 48 | time::pause(); 49 | 50 | let rate_limit = RateLimitLayer::new(3, Duration::from_millis(100)); 51 | let (mut service, mut handle) = mock::spawn_layer(rate_limit); 52 | 53 | assert_ready_ok!(service.poll_ready()); 54 | let response = service.call("hello"); 55 | assert_request_eq!(handle, "hello").send_response("world"); 56 | assert_eq!(response.await.unwrap(), "world"); 57 | 58 | time::advance(Duration::from_millis(100)).await; 59 | 60 | assert_ready_ok!(service.poll_ready()); 61 | let response = service.call("hello"); 62 | assert_request_eq!(handle, "hello").send_response("world"); 63 | assert_eq!(response.await.unwrap(), "world"); 64 | 65 | assert_ready_ok!(service.poll_ready()); 66 | let response = service.call("hello"); 67 | assert_request_eq!(handle, "hello").send_response("world"); 68 | assert_eq!(response.await.unwrap(), "world"); 69 | 70 | assert_ready_ok!(service.poll_ready()); 71 | } 72 | -------------------------------------------------------------------------------- /tower/tests/load_shed/main.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "load-shed")] 2 | #[path = "../support.rs"] 3 | mod support; 4 | 5 | use tokio_test::{assert_ready_err, assert_ready_ok, task}; 6 | use tower::load_shed::LoadShedLayer; 7 | use tower_test::{assert_request_eq, mock}; 8 | 9 | #[tokio::test(flavor = "current_thread")] 10 | async fn when_ready() { 11 | let _t = support::trace_init(); 12 | 13 | let layer = LoadShedLayer::new(); 14 | let (mut service, mut handle) = mock::spawn_layer(layer); 15 | 16 | assert_ready_ok!(service.poll_ready(), "overload always reports ready"); 17 | 18 | let mut response = task::spawn(service.call("hello")); 19 | 20 | assert_request_eq!(handle, "hello").send_response("world"); 21 | assert_eq!(assert_ready_ok!(response.poll()), "world"); 22 | } 23 | 24 | #[tokio::test(flavor = "current_thread")] 25 | async fn when_not_ready() { 26 | let _t = support::trace_init(); 27 | 28 | let layer = LoadShedLayer::new(); 29 | let (mut service, mut handle) = mock::spawn_layer::<_, (), _>(layer); 30 | 31 | handle.allow(0); 32 | 33 | assert_ready_ok!(service.poll_ready(), "overload always reports ready"); 34 | 35 | let mut fut = task::spawn(service.call("hello")); 36 | 37 | let err = assert_ready_err!(fut.poll()); 38 | assert!(err.is::()); 39 | } 40 | -------------------------------------------------------------------------------- /tower/tests/spawn_ready/main.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "spawn-ready")] 2 | #[path = "../support.rs"] 3 | mod support; 4 | 5 | use tokio::time; 6 | use tokio_test::{assert_pending, assert_ready, assert_ready_err, assert_ready_ok}; 7 | use tower::spawn_ready::{SpawnReady, SpawnReadyLayer}; 8 | use tower::util::ServiceExt; 9 | use tower_test::mock; 10 | 11 | #[tokio::test(flavor = "current_thread")] 12 | async fn when_inner_is_not_ready() { 13 | time::pause(); 14 | 15 | let _t = support::trace_init(); 16 | 17 | let layer = SpawnReadyLayer::new(); 18 | let (mut service, mut handle) = mock::spawn_layer::<(), (), _>(layer); 19 | 20 | // Make the service NotReady 21 | handle.allow(0); 22 | 23 | assert_pending!(service.poll_ready()); 24 | 25 | // Make the service is Ready 26 | handle.allow(1); 27 | time::sleep(time::Duration::from_millis(100)).await; 28 | assert_ready_ok!(service.poll_ready()); 29 | } 30 | 31 | #[tokio::test(flavor = "current_thread")] 32 | async fn when_inner_fails() { 33 | let _t = support::trace_init(); 34 | 35 | let layer = SpawnReadyLayer::new(); 36 | let (mut service, mut handle) = mock::spawn_layer::<(), (), _>(layer); 37 | 38 | // Make the service NotReady 39 | handle.allow(0); 40 | handle.send_error("foobar"); 41 | 42 | assert_eq!( 43 | assert_ready_err!(service.poll_ready()).to_string(), 44 | "foobar" 45 | ); 46 | } 47 | 48 | #[tokio::test(flavor = "current_thread")] 49 | async fn propagates_trace_spans() { 50 | use tracing::Instrument; 51 | 52 | let _t = support::trace_init(); 53 | 54 | let span = tracing::info_span!("my_span"); 55 | 56 | let service = support::AssertSpanSvc::new(span.clone()); 57 | let service = SpawnReady::new(service); 58 | let result = tokio::spawn(service.oneshot(()).instrument(span)); 59 | 60 | result.await.expect("service panicked").expect("failed"); 61 | } 62 | 63 | #[cfg(test)] 64 | #[tokio::test(flavor = "current_thread")] 65 | async fn abort_on_drop() { 66 | let (mock, mut handle) = mock::pair::<(), ()>(); 67 | let mut svc = SpawnReady::new(mock); 68 | handle.allow(0); 69 | 70 | // Drive the service to readiness until we signal a drop. 71 | let (drop_tx, drop_rx) = tokio::sync::oneshot::channel(); 72 | let mut task = tokio_test::task::spawn(async move { 73 | tokio::select! { 74 | _ = drop_rx => {} 75 | _ = svc.ready() => unreachable!("Service must not become ready"), 76 | } 77 | }); 78 | assert_pending!(task.poll()); 79 | assert_pending!(handle.poll_request()); 80 | 81 | // End the task and ensure that the inner service has been dropped. 82 | assert!(drop_tx.send(()).is_ok()); 83 | tokio_test::assert_ready!(task.poll()); 84 | tokio::task::yield_now().await; 85 | assert!(tokio_test::assert_ready!(handle.poll_request()).is_none()); 86 | } 87 | -------------------------------------------------------------------------------- /tower/tests/steer/main.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "steer")] 2 | #[path = "../support.rs"] 3 | mod support; 4 | 5 | use std::{ 6 | future::{ready, Ready}, 7 | task::{Context, Poll}, 8 | }; 9 | use tower::steer::Steer; 10 | use tower_service::Service; 11 | 12 | type StdError = Box; 13 | 14 | struct MyService(u8, bool); 15 | 16 | impl Service for MyService { 17 | type Response = u8; 18 | type Error = StdError; 19 | type Future = Ready>; 20 | 21 | fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { 22 | if !self.1 { 23 | Poll::Pending 24 | } else { 25 | Poll::Ready(Ok(())) 26 | } 27 | } 28 | 29 | fn call(&mut self, _req: String) -> Self::Future { 30 | ready(Ok(self.0)) 31 | } 32 | } 33 | 34 | #[tokio::test(flavor = "current_thread")] 35 | async fn pick_correctly() { 36 | let _t = support::trace_init(); 37 | let srvs = vec![MyService(42, true), MyService(57, true)]; 38 | let mut st = Steer::new(srvs, |_: &_, _: &[_]| 1); 39 | 40 | std::future::poll_fn(|cx| st.poll_ready(cx)).await.unwrap(); 41 | let r = st.call(String::from("foo")).await.unwrap(); 42 | assert_eq!(r, 57); 43 | } 44 | 45 | #[tokio::test(flavor = "current_thread")] 46 | async fn pending_all_ready() { 47 | let _t = support::trace_init(); 48 | 49 | let srvs = vec![MyService(42, true), MyService(57, false)]; 50 | let mut st = Steer::new(srvs, |_: &_, _: &[_]| 0); 51 | 52 | let p = futures_util::poll!(std::future::poll_fn(|cx| st.poll_ready(cx))); 53 | match p { 54 | Poll::Pending => (), 55 | _ => panic!( 56 | "Steer should not return poll_ready if at least one component service is not ready" 57 | ), 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /tower/tests/support.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use std::fmt; 4 | use std::future; 5 | use std::pin::Pin; 6 | use std::task::{Context, Poll}; 7 | use tokio::sync::mpsc; 8 | use tokio_stream::Stream; 9 | use tower::Service; 10 | 11 | pub(crate) fn trace_init() -> tracing::subscriber::DefaultGuard { 12 | let subscriber = tracing_subscriber::fmt() 13 | .with_test_writer() 14 | .with_max_level(tracing::Level::TRACE) 15 | .with_thread_names(true) 16 | .finish(); 17 | tracing::subscriber::set_default(subscriber) 18 | } 19 | 20 | pin_project_lite::pin_project! { 21 | #[derive(Clone, Debug)] 22 | pub struct IntoStream { 23 | #[pin] 24 | inner: S 25 | } 26 | } 27 | 28 | impl IntoStream { 29 | pub fn new(inner: S) -> Self { 30 | Self { inner } 31 | } 32 | } 33 | 34 | impl Stream for IntoStream> { 35 | type Item = I; 36 | 37 | fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { 38 | self.project().inner.poll_recv(cx) 39 | } 40 | } 41 | 42 | impl Stream for IntoStream> { 43 | type Item = I; 44 | 45 | fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { 46 | self.project().inner.poll_recv(cx) 47 | } 48 | } 49 | 50 | #[derive(Clone, Debug)] 51 | pub struct AssertSpanSvc { 52 | span: tracing::Span, 53 | polled: bool, 54 | } 55 | 56 | pub struct AssertSpanError(String); 57 | 58 | impl fmt::Debug for AssertSpanError { 59 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 60 | fmt::Display::fmt(&self.0, f) 61 | } 62 | } 63 | 64 | impl fmt::Display for AssertSpanError { 65 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 66 | fmt::Display::fmt(&self.0, f) 67 | } 68 | } 69 | 70 | impl std::error::Error for AssertSpanError {} 71 | 72 | impl AssertSpanSvc { 73 | pub fn new(span: tracing::Span) -> Self { 74 | Self { 75 | span, 76 | polled: false, 77 | } 78 | } 79 | 80 | fn check(&self, func: &str) -> Result<(), AssertSpanError> { 81 | let current_span = tracing::Span::current(); 82 | tracing::debug!(?current_span, ?self.span, %func); 83 | if current_span == self.span { 84 | return Ok(()); 85 | } 86 | 87 | Err(AssertSpanError(format!( 88 | "{} called outside expected span\n expected: {:?}\n current: {:?}", 89 | func, self.span, current_span 90 | ))) 91 | } 92 | } 93 | 94 | impl Service<()> for AssertSpanSvc { 95 | type Response = (); 96 | type Error = AssertSpanError; 97 | type Future = future::Ready>; 98 | 99 | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { 100 | if self.polled { 101 | return Poll::Ready(self.check("poll_ready")); 102 | } 103 | 104 | cx.waker().wake_by_ref(); 105 | self.polled = true; 106 | Poll::Pending 107 | } 108 | 109 | fn call(&mut self, _: ()) -> Self::Future { 110 | future::ready(self.check("call")) 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /tower/tests/util/main.rs: -------------------------------------------------------------------------------- 1 | #![cfg(feature = "util")] 2 | #![allow(clippy::type_complexity)] 3 | 4 | mod call_all; 5 | mod oneshot; 6 | mod service_fn; 7 | #[path = "../support.rs"] 8 | pub(crate) mod support; 9 | -------------------------------------------------------------------------------- /tower/tests/util/oneshot.rs: -------------------------------------------------------------------------------- 1 | use std::task::{Context, Poll}; 2 | use std::{future::Future, pin::Pin}; 3 | use tower::util::ServiceExt; 4 | use tower_service::Service; 5 | 6 | #[tokio::test(flavor = "current_thread")] 7 | async fn service_driven_to_readiness() { 8 | // This test ensures that `oneshot` will repeatedly call `poll_ready` until 9 | // the service is ready. 10 | let _t = super::support::trace_init(); 11 | 12 | struct PollMeTwice { 13 | ready: bool, 14 | } 15 | impl Service<()> for PollMeTwice { 16 | type Error = (); 17 | type Response = (); 18 | type Future = Pin< 19 | Box> + Send + Sync + 'static>, 20 | >; 21 | 22 | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { 23 | if self.ready { 24 | Poll::Ready(Ok(())) 25 | } else { 26 | self.ready = true; 27 | cx.waker().wake_by_ref(); 28 | Poll::Pending 29 | } 30 | } 31 | 32 | fn call(&mut self, _: ()) -> Self::Future { 33 | assert!(self.ready, "service not driven to readiness!"); 34 | Box::pin(async { Ok(()) }) 35 | } 36 | } 37 | 38 | let svc = PollMeTwice { ready: false }; 39 | svc.oneshot(()).await.unwrap(); 40 | } 41 | -------------------------------------------------------------------------------- /tower/tests/util/service_fn.rs: -------------------------------------------------------------------------------- 1 | use std::future::ready; 2 | use tower::util::service_fn; 3 | use tower_service::Service; 4 | 5 | #[tokio::test(flavor = "current_thread")] 6 | async fn simple() { 7 | let _t = super::support::trace_init(); 8 | 9 | let mut add_one = service_fn(|req| ready(Ok::<_, ()>(req + 1))); 10 | let answer = add_one.call(1).await.unwrap(); 11 | assert_eq!(answer, 2); 12 | } 13 | --------------------------------------------------------------------------------