Repository: tower-rs/tower
Pull request #352 (2019-09-23 20:53:41)

Consistently apply deny/warn rules
This makes all tower subcrates have the following lints as warn (rather than allow): `missing_docs`, `rust_2018_idioms`, and `missing_debug_implementations`. In addition, it consistently applies `deny(warning)` *only* under `#[cfg(test)]` so that deprecations and macro changes in minor version bumps in dependencies will never cause `tower` crates to stop compiling.

Note that `tower-reconnect` has the `missing_docs` lint disabled for now since it contained _no_ documentation previously. Also note that this patch does not add documentation to the various `new` methods, as they are considered self-explanatory. They are instead marked as`#[allow(missing_docs)]`.

LucioFranco: @jonhoo would you rather deny on test or on CI? I feel like CI may be better?
jonhoo: Do we even have a ci feature? I'm happy for deny to be on `test`, since it means that the errors also appear locally during development.
LucioFranco: @jonhoo we can do it via a env var. I actually think I prefer CI to deny since you may want to test code but may not have resolved all the warnings like docs.

Patch:
diff --git a/tower-balance/src/lib.rs b/tower-balance/src/lib.rs
index cc4c81e..33e3e12 100644
--- a/tower-balance/src/lib.rs
+++ b/tower-balance/src/lib.rs
@@ -1,10 +1,13 @@
 //! Load balancing middlewares.
 
 #![doc(html_root_url = "https://docs.rs/tower-balance/0.3.0-alpha.1")]
-#![deny(missing_docs)]
-#![deny(rust_2018_idioms)]
+#![warn(
+    missing_debug_implementations,
+    missing_docs,
+    rust_2018_idioms,
+    unreachable_pub
+)]
 #![allow(elided_lifetimes_in_paths)]
-#![deny(warnings)]
 
 pub mod error;
 pub mod p2c;
diff --git a/tower-balance/src/p2c/make.rs b/tower-balance/src/p2c/make.rs
index 85386f8..22e703d 100644
--- a/tower-balance/src/p2c/make.rs
+++ b/tower-balance/src/p2c/make.rs
@@ -19,8 +19,9 @@ pub struct BalanceMake<S, Req> {
     _marker: PhantomData<fn(Req)>,
 }
 
-#[pin_project]
 /// Makes a balancer instance.
+#[pin_project]
+#[derive(Debug)]
 pub struct MakeFuture<F, Req> {
     #[pin]
     inner: F,
diff --git a/tower-balance/src/p2c/service.rs b/tower-balance/src/p2c/service.rs
index 2b9b3f1..ddc9b8f 100644
--- a/tower-balance/src/p2c/service.rs
+++ b/tower-balance/src/p2c/service.rs
@@ -6,6 +6,7 @@ use pin_project::pin_project;
 use rand::{rngs::SmallRng, FromEntropy};
 use std::marker::PhantomData;
 use std::{
+    fmt,
     future::Future,
     pin::Pin,
     task::{Context, Poll},
@@ -36,7 +37,6 @@ use tracing::{debug, trace};
 /// [p2c]: http://www.eecs.harvard.edu/~michaelm/postscripts/handbook2001.pdf
 /// [`Box::pin`]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.pin
 /// [#319]: https://github.com/tower-rs/tower/issues/319
-#[derive(Debug)]
 pub struct Balance<D: Discover, Req> {
     discover: D,
 
@@ -54,6 +54,23 @@ pub struct Balance<D: Discover, Req> {
     _req: PhantomData<Req>,
 }
 
+impl<D: Discover, Req> fmt::Debug for Balance<D, Req>
+where
+    D: fmt::Debug,
+    D::Key: fmt::Debug,
+    D::Service: fmt::Debug,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("Balance")
+            .field("discover", &self.discover)
+            .field("ready_services", &self.ready_services)
+            .field("unready_services", &self.unready_services)
+            .field("cancelations", &self.cancelations)
+            .field("next_ready_index", &self.next_ready_index)
+            .finish()
+    }
+}
+
 #[pin_project]
 /// A Future that becomes satisfied when an `S`-typed service is ready.
 ///
diff --git a/tower-balance/src/pool/mod.rs b/tower-balance/src/pool/mod.rs
index 20aa3e9..92b54ab 100644
--- a/tower-balance/src/pool/mod.rs
+++ b/tower-balance/src/pool/mod.rs
@@ -20,6 +20,7 @@ use futures_core::ready;
 use pin_project::pin_project;
 use slab::Slab;
 use std::{
+    fmt,
     future::Future,
     pin::Pin,
     task::{Context, Poll},
@@ -42,9 +43,9 @@ enum Level {
     High,
 }
 
-#[pin_project]
 /// A wrapper around `MakeService` that discovers a new service when load is high, and removes a
 /// service when load is low. See [`Pool`].
+#[pin_project]
 pub struct PoolDiscoverer<MS, Target, Request>
 where
     MS: MakeService<Target, Request>,
@@ -61,6 +62,23 @@ where
     limit: Option<usize>,
 }
 
+impl<MS, Target, Request> fmt::Debug for PoolDiscoverer<MS, Target, Request>
+where
+    MS: MakeService<Target, Request> + fmt::Debug,
+    Target: fmt::Debug,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("PoolDiscoverer")
+            .field("maker", &self.maker)
+            .field("making", &self.making.is_some())
+            .field("target", &self.target)
+            .field("load", &self.load)
+            .field("services", &self.services)
+            .field("limit", &self.limit)
+            .finish()
+    }
+}
+
 impl<MS, Target, Request> Discover for PoolDiscoverer<MS, Target, Request>
 where
     MS: MakeService<Target, Request>,
@@ -298,6 +316,23 @@ where
     ewma: f64,
 }
 
+impl<MS, Target, Request> fmt::Debug for Pool<MS, Target, Request>
+where
+    MS: MakeService<Target, Request> + fmt::Debug,
+    MS::MakeError: Into<error::Error>,
+    MS::Error: Into<error::Error>,
+    Target: Clone + fmt::Debug,
+    MS::Service: fmt::Debug,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("Pool")
+            .field("balance", &self.balance)
+            .field("options", &self.options)
+            .field("ewma", &self.ewma)
+            .finish()
+    }
+}
+
 impl<MS, Target, Request> Pool<MS, Target, Request>
 where
     MS: MakeService<Target, Request>,
@@ -396,6 +431,7 @@ where
 }
 
 #[doc(hidden)]
+#[derive(Debug)]
 pub struct DropNotifyService<Svc> {
     svc: Svc,
     id: usize,
diff --git a/tower-buffer/src/future.rs b/tower-buffer/src/future.rs
index 00b7bc1..e0ae620 100644
--- a/tower-buffer/src/future.rs
+++ b/tower-buffer/src/future.rs
@@ -14,12 +14,14 @@ use std::{
 
 /// Future eventually completed with the response to the original request.
 #[pin_project]
+#[derive(Debug)]
 pub struct ResponseFuture<T> {
     #[pin]
     state: ResponseState<T>,
 }
 
 #[pin_project]
+#[derive(Debug)]
 enum ResponseState<T> {
     Failed(Option<Error>),
     Rx(#[pin] message::Rx<T>),
diff --git a/tower-buffer/src/layer.rs b/tower-buffer/src/layer.rs
index 009d3be..d6af0fb 100644
--- a/tower-buffer/src/layer.rs
+++ b/tower-buffer/src/layer.rs
@@ -12,6 +12,7 @@ pub struct BufferLayer<Request, E = DefaultExecutor> {
 }
 
 impl<Request> BufferLayer<Request, DefaultExecutor> {
+    #[allow(missing_docs)]
     pub fn new(bound: usize) -> Self {
         BufferLayer {
             bound,
@@ -22,6 +23,7 @@ impl<Request> BufferLayer<Request, DefaultExecutor> {
 }
 
 impl<Request, E: Clone> BufferLayer<Request, E> {
+    /// Create a new buffered service layer spawned on the given executor.
     pub fn with_executor(bound: usize, executor: E) -> Self {
         BufferLayer {
             bound,
diff --git a/tower-buffer/src/lib.rs b/tower-buffer/src/lib.rs
index a6c00bd..6280be2 100644
--- a/tower-buffer/src/lib.rs
+++ b/tower-buffer/src/lib.rs
@@ -1,5 +1,10 @@
 #![doc(html_root_url = "https://docs.rs/tower-buffer/0.3.0-alpha.1a")]
-#![deny(rust_2018_idioms)]
+#![warn(
+    missing_debug_implementations,
+    missing_docs,
+    rust_2018_idioms,
+    unreachable_pub
+)]
 #![allow(elided_lifetimes_in_paths)]
 
 //! Buffer requests when the inner service is out of capacity.
diff --git a/tower-buffer/src/service.rs b/tower-buffer/src/service.rs
index 1f2e7ee..17c94e0 100644
--- a/tower-buffer/src/service.rs
+++ b/tower-buffer/src/service.rs
@@ -14,6 +14,7 @@ use tower_service::Service;
 /// Adds a buffer in front of an inner service.
 ///
 /// See crate level documentation for more details.
+#[derive(Debug)]
 pub struct Buffer<T, Request>
 where
     T: Service<Request>,
diff --git a/tower-buffer/src/worker.rs b/tower-buffer/src/worker.rs
index dbfe436..d7e6fec 100644
--- a/tower-buffer/src/worker.rs
+++ b/tower-buffer/src/worker.rs
@@ -22,6 +22,7 @@ use tower_service::Service;
 /// types in public traits that are not meant for consumers of the library to
 /// implement (only call).
 #[pin_project]
+#[derive(Debug)]
 pub struct Worker<T, Request>
 where
     T: Service<Request>,
@@ -36,6 +37,7 @@ where
 }
 
 /// Get the error out
+#[derive(Debug)]
 pub(crate) struct Handle {
     inner: Arc<Mutex<Option<ServiceError>>>,
 }
diff --git a/tower-discover/src/lib.rs b/tower-discover/src/lib.rs
index eba95d0..d627ce0 100644
--- a/tower-discover/src/lib.rs
+++ b/tower-discover/src/lib.rs
@@ -1,5 +1,10 @@
 #![doc(html_root_url = "https://docs.rs/tower-discover/0.3.0-alpha.1")]
-#![deny(rust_2018_idioms)]
+#![warn(
+    missing_debug_implementations,
+    missing_docs,
+    rust_2018_idioms,
+    unreachable_pub
+)]
 #![allow(elided_lifetimes_in_paths)]
 
 //! # Tower service discovery
@@ -32,6 +37,7 @@ pub trait Discover {
     /// NewService key
     type Key: Hash + Eq;
 
+    /// The type of `Service` yielded by this `Discover`.
     type Service;
 
     /// Error produced during discovery
@@ -88,7 +94,10 @@ impl<D: ?Sized + Discover + Unpin> Discover for Box<D> {
 }
 
 /// A change in the service set
+#[derive(Debug)]
 pub enum Change<K, V> {
+    /// A new service identified by key `K` was identified.
     Insert(K, V),
+    /// The service identified by key `K` disappeared.
     Remove(K),
 }
diff --git a/tower-discover/src/list.rs b/tower-discover/src/list.rs
index 1e3b743..a10cf1d 100644
--- a/tower-discover/src/list.rs
+++ b/tower-discover/src/list.rs
@@ -12,6 +12,7 @@ use tower_service::Service;
 /// `ServiceList` is created with an initial list of services. The discovery
 /// process will yield this list once and do nothing after.
 #[pin_project]
+#[derive(Debug)]
 pub struct ServiceList<T>
 where
     T: IntoIterator,
@@ -23,6 +24,7 @@ impl<T, U> ServiceList<T>
 where
     T: IntoIterator<Item = U>,
 {
+    #[allow(missing_docs)]
     pub fn new<Request>(services: T) -> ServiceList<T>
     where
         U: Service<Request>,
diff --git a/tower-discover/src/stream.rs b/tower-discover/src/stream.rs
index 4f7a2c0..68e3556 100644
--- a/tower-discover/src/stream.rs
+++ b/tower-discover/src/stream.rs
@@ -10,12 +10,14 @@ use tower_service::Service;
 
 /// Dynamic service discovery based on a stream of service changes.
 #[pin_project]
+#[derive(Debug)]
 pub struct ServiceStream<S> {
     #[pin]
     inner: S,
 }
 
 impl<S> ServiceStream<S> {
+    #[allow(missing_docs)]
     pub fn new<K, Svc, Request>(services: S) -> Self
     where
         S: TryStream<Ok = Change<K, Svc>>,
diff --git a/tower-filter/src/layer.rs b/tower-filter/src/layer.rs
index d6735f4..a779b29 100644
--- a/tower-filter/src/layer.rs
+++ b/tower-filter/src/layer.rs
@@ -1,11 +1,14 @@
 use crate::Filter;
 use tower_layer::Layer;
 
+/// Conditionally dispatch requests to the inner service based on a predicate.
+#[derive(Debug)]
 pub struct FilterLayer<U> {
     predicate: U,
 }
 
 impl<U> FilterLayer<U> {
+    #[allow(missing_docs)]
     pub fn new(predicate: U) -> Self {
         FilterLayer { predicate }
     }
diff --git a/tower-filter/src/lib.rs b/tower-filter/src/lib.rs
index 307248a..9c6af92 100644
--- a/tower-filter/src/lib.rs
+++ b/tower-filter/src/lib.rs
@@ -1,5 +1,10 @@
 #![doc(html_root_url = "https://docs.rs/tower-filter/0.3.0-alpha.1")]
-#![deny(rust_2018_idioms)]
+#![warn(
+    missing_debug_implementations,
+    missing_docs,
+    rust_2018_idioms,
+    unreachable_pub
+)]
 #![allow(elided_lifetimes_in_paths)]
 
 //! Conditionally dispatch requests to the inner service based on the result of
@@ -17,6 +22,7 @@ use futures_core::ready;
 use std::task::{Context, Poll};
 use tower_service::Service;
 
+/// Conditionally dispatch requests to the inner service based on a predicate.
 #[derive(Clone, Debug)]
 pub struct Filter<T, U> {
     inner: T,
@@ -24,6 +30,7 @@ pub struct Filter<T, U> {
 }
 
 impl<T, U> Filter<T, U> {
+    #[allow(missing_docs)]
     pub fn new(inner: T, predicate: U) -> Self {
         Filter { inner, predicate }
     }
diff --git a/tower-filter/src/predicate.rs b/tower-filter/src/predicate.rs
index 6f842d1..34d2e58 100644
--- a/tower-filter/src/predicate.rs
+++ b/tower-filter/src/predicate.rs
@@ -3,8 +3,12 @@ use std::future::Future;
 
 /// Checks a request
 pub trait Predicate<Request> {
+    /// The future returned by `check`.
     type Future: Future<Output = Result<(), Error>>;
 
+    /// Check whether the given request should be forwarded.
+    ///
+    /// If the future resolves with `Ok`, the request is forwarded to the inner service.
     fn check(&mut self, request: &Request) -> Self::Future;
 }
 
diff --git a/tower-hedge/src/lib.rs b/tower-hedge/src/lib.rs
index c95638b..c621cdb 100644
--- a/tower-hedge/src/lib.rs
+++ b/tower-hedge/src/lib.rs
@@ -1,8 +1,12 @@
 //! Pre-emptively retry requests which have been outstanding for longer
 //! than a given latency percentile.
 
-#![deny(warnings)]
-#![deny(missing_docs)]
+#![warn(
+    missing_debug_implementations,
+    missing_docs,
+    rust_2018_idioms,
+    unreachable_pub
+)]
 
 use futures_util::future;
 use log::error;
@@ -37,8 +41,9 @@ type Service<S, P> = select::Select<
 #[derive(Debug)]
 pub struct Hedge<S, P>(Service<S, P>);
 
-#[pin_project]
 /// The Future returned by the hedge Service.
+#[pin_project]
+#[derive(Debug)]
 pub struct Future<S, Request>
 where
     S: tower_service::Service<Request>,
diff --git a/tower-hedge/src/rotating_histogram.rs b/tower-hedge/src/rotating_histogram.rs
index 0fbb965..87fb8a7 100644
--- a/tower-hedge/src/rotating_histogram.rs
+++ b/tower-hedge/src/rotating_histogram.rs
@@ -1,5 +1,3 @@
-extern crate tokio_timer;
-
 use hdrhistogram::Histogram;
 use log::trace;
 use std::time::{Duration, Instant};
diff --git a/tower-layer/src/lib.rs b/tower-layer/src/lib.rs
index b6d9050..cf728ce 100644
--- a/tower-layer/src/lib.rs
+++ b/tower-layer/src/lib.rs
@@ -1,5 +1,10 @@
 #![doc(html_root_url = "https://docs.rs/tower-layer/0.3.0-alpha.1")]
-#![deny(missing_docs, rust_2018_idioms)]
+#![warn(
+    missing_debug_implementations,
+    missing_docs,
+    rust_2018_idioms,
+    unreachable_pub
+)]
 
 //! Layer traits and extensions.
 //!
diff --git a/tower-limit/src/lib.rs b/tower-limit/src/lib.rs
index 5da1896..7284fb3 100644
--- a/tower-limit/src/lib.rs
+++ b/tower-limit/src/lib.rs
@@ -1,6 +1,10 @@
 #![doc(html_root_url = "https://docs.rs/tower-limit/0.3.0-alpha.1")]
-#![cfg_attr(test, deny(warnings))]
-#![deny(missing_debug_implementations, missing_docs, rust_2018_idioms)]
+#![warn(
+    missing_debug_implementations,
+    missing_docs,
+    rust_2018_idioms,
+    unreachable_pub
+)]
 #![allow(elided_lifetimes_in_paths)]
 
 //! Tower middleware for limiting requests.
diff --git a/tower-load-shed/src/lib.rs b/tower-load-shed/src/lib.rs
index 38e7da4..457b600 100644
--- a/tower-load-shed/src/lib.rs
+++ b/tower-load-shed/src/lib.rs
@@ -1,6 +1,10 @@
 #![doc(html_root_url = "https://docs.rs/tower-load-shed/0.3.0-alpha.1")]
-#![cfg_attr(test, deny(warnings))]
-#![deny(missing_debug_implementations, missing_docs, rust_2018_idioms)]
+#![warn(
+    missing_debug_implementations,
+    missing_docs,
+    rust_2018_idioms,
+    unreachable_pub
+)]
 #![allow(elided_lifetimes_in_paths)]
 
 //! Tower middleware for shedding load when inner services aren't ready.
diff --git a/tower-load/src/lib.rs b/tower-load/src/lib.rs
index c540b0e..bc06c2b 100644
--- a/tower-load/src/lib.rs
+++ b/tower-load/src/lib.rs
@@ -1,9 +1,12 @@
 //! Abstractions and utilties for measuring a service's load.
 
 #![doc(html_root_url = "https://docs.rs/tower-load/0.3.0-alpha.1")]
-#![deny(missing_docs)]
-#![deny(rust_2018_idioms)]
-#![deny(warnings)]
+#![warn(
+    missing_debug_implementations,
+    missing_docs,
+    rust_2018_idioms,
+    unreachable_pub
+)]
 #![allow(elided_lifetimes_in_paths)]
 
 mod constant;
diff --git a/tower-load/src/peak_ewma.rs b/tower-load/src/peak_ewma.rs
index d34a289..055f97c 100644
--- a/tower-load/src/peak_ewma.rs
+++ b/tower-load/src/peak_ewma.rs
@@ -42,6 +42,7 @@ use tower_service::Service;
 ///
 /// [finagle]:
 /// https://github.com/twitter/finagle/blob/9cc08d15216497bb03a1cafda96b7266cfbbcff1/finagle-core/src/main/scala/com/twitter/finagle/loadbalancer/PeakEwma.scala
+#[derive(Debug)]
 pub struct PeakEwma<S, I = NoInstrument> {
     service: S,
     decay_ns: f64,
@@ -51,6 +52,7 @@ pub struct PeakEwma<S, I = NoInstrument> {
 
 /// Wraps a `D`-typed stream of discovery updates with `PeakEwma`.
 #[pin_project]
+#[derive(Debug)]
 pub struct PeakEwmaDiscover<D, I = NoInstrument> {
     #[pin]
     discover: D,
@@ -67,6 +69,7 @@ pub struct PeakEwmaDiscover<D, I = NoInstrument> {
 pub struct Cost(f64);
 
 /// Tracks an in-flight request and updates the RTT-estimate on Drop.
+#[derive(Debug)]
 pub struct Handle {
     sent_at: Instant,
     decay_ns: f64,
@@ -74,6 +77,7 @@ pub struct Handle {
 }
 
 /// Holds the current RTT estimate and the last time this value was updated.
+#[derive(Debug)]
 struct RttEstimate {
     update_at: Instant,
     rtt_ns: f64,
diff --git a/tower-load/src/pending_requests.rs b/tower-load/src/pending_requests.rs
index d21f494..74c5b15 100644
--- a/tower-load/src/pending_requests.rs
+++ b/tower-load/src/pending_requests.rs
@@ -135,7 +135,7 @@ where
 // ==== RefCount ====
 
 impl RefCount {
-    pub fn ref_count(&self) -> usize {
+    pub(crate) fn ref_count(&self) -> usize {
         Arc::strong_count(&self.0)
     }
 }
diff --git a/tower-make/src/lib.rs b/tower-make/src/lib.rs
index 0701b78..50973bb 100644
--- a/tower-make/src/lib.rs
+++ b/tower-make/src/lib.rs
@@ -1,5 +1,10 @@
 #![doc(html_root_url = "https://docs.rs/tower-make/0.3.0-alpha.2")]
-#![deny(rust_2018_idioms)]
+#![warn(
+    missing_debug_implementations,
+    missing_docs,
+    rust_2018_idioms,
+    unreachable_pub
+)]
 
 //! Trait aliases for Services that produce specific types of Responses.
 
diff --git a/tower-reconnect/src/future.rs b/tower-reconnect/src/future.rs
index 719dbfa..1627731 100644
--- a/tower-reconnect/src/future.rs
+++ b/tower-reconnect/src/future.rs
@@ -7,6 +7,7 @@ use std::{
 };
 
 #[pin_project]
+#[derive(Debug)]
 pub struct ResponseFuture<F> {
     #[pin]
     inner: F,
diff --git a/tower-reconnect/src/lib.rs b/tower-reconnect/src/lib.rs
index 458666d..f726d6d 100644
--- a/tower-reconnect/src/lib.rs
+++ b/tower-reconnect/src/lib.rs
@@ -1,5 +1,6 @@
 #![doc(html_root_url = "https://docs.rs/tower-reconnect/0.3.0-alpha.1")]
-#![deny(rust_2018_idioms)]
+#![warn(missing_debug_implementations, rust_2018_idioms, unreachable_pub)]
+#![allow(missing_docs)] // TODO
 #![allow(elided_lifetimes_in_paths)]
 
 pub mod future;
diff --git a/tower-retry/src/lib.rs b/tower-retry/src/lib.rs
index 0e66bea..80876ac 100644
--- a/tower-retry/src/lib.rs
+++ b/tower-retry/src/lib.rs
@@ -1,6 +1,10 @@
 #![doc(html_root_url = "https://docs.rs/tower-retry/0.3.0-alpha.1")]
-#![deny(missing_docs, missing_debug_implementations, rust_2018_idioms)]
-#![cfg_attr(test, deny(warnings))]
+#![warn(
+    missing_debug_implementations,
+    missing_docs,
+    rust_2018_idioms,
+    unreachable_pub
+)]
 #![allow(elided_lifetimes_in_paths)]
 
 //! Tower middleware for retrying "failed" requests.
diff --git a/tower-service/src/lib.rs b/tower-service/src/lib.rs
index e1ddebc..bc6dc25 100644
--- a/tower-service/src/lib.rs
+++ b/tower-service/src/lib.rs
@@ -1,5 +1,10 @@
-#![deny(missing_docs)]
 #![doc(html_root_url = "https://docs.rs/tower-service/0.3.0-alpha.1")]
+#![warn(
+    missing_debug_implementations,
+    missing_docs,
+    rust_2018_idioms,
+    unreachable_pub
+)]
 
 //! Definition of the core `Service` trait to Tower
 //!
diff --git a/tower-spawn-ready/src/future.rs b/tower-spawn-ready/src/future.rs
index fb31641..1e0463a 100644
--- a/tower-spawn-ready/src/future.rs
+++ b/tower-spawn-ready/src/future.rs
@@ -13,8 +13,9 @@ use tokio_executor::TypedExecutor;
 use tokio_sync::oneshot;
 use tower_service::Service;
 
-#[pin_project]
 /// Drives a service to readiness.
+#[pin_project]
+#[derive(Debug)]
 pub struct BackgroundReady<T, Request> {
     service: Option<T>,
     tx: Option<oneshot::Sender<Result<T, Error>>>,
diff --git a/tower-spawn-ready/src/lib.rs b/tower-spawn-ready/src/lib.rs
index ca8eb2d..8a2180f 100644
--- a/tower-spawn-ready/src/lib.rs
+++ b/tower-spawn-ready/src/lib.rs
@@ -1,5 +1,10 @@
 #![doc(html_root_url = "https://docs.rs/tower-spawn-ready/0.3.0-alpha.1")]
-#![deny(missing_docs, rust_2018_idioms, warnings)]
+#![warn(
+    missing_debug_implementations,
+    missing_docs,
+    rust_2018_idioms,
+    unreachable_pub
+)]
 #![allow(elided_lifetimes_in_paths)]
 
 //! When an underlying service is not ready, drive it to readiness on a
diff --git a/tower-spawn-ready/src/service.rs b/tower-spawn-ready/src/service.rs
index cc80a68..d2880e0 100644
--- a/tower-spawn-ready/src/service.rs
+++ b/tower-spawn-ready/src/service.rs
@@ -16,10 +16,12 @@ use tower_service::Service;
 /// Spawns tasks to drive an inner service to readiness.
 ///
 /// See crate level documentation for more details.
+#[derive(Debug)]
 pub struct SpawnReady<T> {
     inner: Inner<T>,
 }
 
+#[derive(Debug)]
 enum Inner<T> {
     Service(Option<T>),
     Future(oneshot::Receiver<Result<T, Error>>),
diff --git a/tower-timeout/src/error.rs b/tower-timeout/src/error.rs
index a647e27..daf4bd8 100644
--- a/tower-timeout/src/error.rs
+++ b/tower-timeout/src/error.rs
@@ -16,7 +16,7 @@ impl Elapsed {
 }
 
 impl fmt::Display for Elapsed {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.pad("request timed out")
     }
 }
diff --git a/tower-timeout/src/lib.rs b/tower-timeout/src/lib.rs
index 140336a..e9f9405 100644
--- a/tower-timeout/src/lib.rs
+++ b/tower-timeout/src/lib.rs
@@ -1,7 +1,10 @@
 #![doc(html_root_url = "https://docs.rs/tower-timeout/0.3.0-alpha.1")]
-#![deny(missing_debug_implementations, missing_docs, rust_2018_idioms)]
-#![allow(elided_lifetimes_in_paths)]
-#![cfg_attr(test, deny(warnings))]
+#![warn(
+    missing_debug_implementations,
+    missing_docs,
+    rust_2018_idioms,
+    unreachable_pub
+)]
 
 //! Tower middleware that applies a timeout to requests.
 //!
diff --git a/tower-util/src/boxed/mod.rs b/tower-util/src/boxed/mod.rs
index 9a55ab7..5fb9faf 100644
--- a/tower-util/src/boxed/mod.rs
+++ b/tower-util/src/boxed/mod.rs
@@ -32,4 +32,5 @@
 mod sync;
 mod unsync;
 
+#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411
 pub use self::{sync::BoxService, unsync::UnsyncBoxService};
diff --git a/tower-util/src/boxed/sync.rs b/tower-util/src/boxed/sync.rs
index e7926ec..b3a9f89 100644
--- a/tower-util/src/boxed/sync.rs
+++ b/tower-util/src/boxed/sync.rs
@@ -30,6 +30,7 @@ struct Boxed<S> {
 }
 
 impl<T, U, E> BoxService<T, U, E> {
+    #[allow(missing_docs)]
     pub fn new<S>(inner: S) -> Self
     where
         S: Service<T, Response = U, Error = E> + Send + 'static,
diff --git a/tower-util/src/boxed/unsync.rs b/tower-util/src/boxed/unsync.rs
index ff8f3f6..ef15682 100644
--- a/tower-util/src/boxed/unsync.rs
+++ b/tower-util/src/boxed/unsync.rs
@@ -24,6 +24,7 @@ struct UnsyncBoxed<S> {
 }
 
 impl<T, U, E> UnsyncBoxService<T, U, E> {
+    #[allow(missing_docs)]
     pub fn new<S>(inner: S) -> Self
     where
         S: Service<T, Response = U, Error = E> + 'static,
diff --git a/tower-util/src/call_all/mod.rs b/tower-util/src/call_all/mod.rs
index 9921ffe..ee6e73d 100644
--- a/tower-util/src/call_all/mod.rs
+++ b/tower-util/src/call_all/mod.rs
@@ -4,6 +4,7 @@ mod common;
 mod ordered;
 mod unordered;
 
+#[allow(unreachable_pub)] // https://github.com/rust-lang/rust/issues/57411
 pub use self::{ordered::CallAll, unordered::CallAllUnordered};
 
 type Error = Box<dyn std::error::Error + Send + Sync>;
diff --git a/tower-util/src/either.rs b/tower-util/src/either.rs
index dcd3a5c..1912188 100644
--- a/tower-util/src/either.rs
+++ b/tower-util/src/either.rs
@@ -19,7 +19,9 @@ use tower_service::Service;
 #[pin_project]
 #[derive(Clone, Debug)]
 pub enum Either<A, B> {
+    /// One type of backing `Service`.
     A(#[pin] A),
+    /// The other type of backing `Service`.
     B(#[pin] B),
 }
 
diff --git a/tower-util/src/lib.rs b/tower-util/src/lib.rs
index 5c58991..3917a50 100644
--- a/tower-util/src/lib.rs
+++ b/tower-util/src/lib.rs
@@ -1,5 +1,10 @@
 #![doc(html_root_url = "https://docs.rs/tower-util/0.3.0-alpha.1")]
-#![deny(rust_2018_idioms)]
+#![warn(
+    missing_debug_implementations,
+    missing_docs,
+    rust_2018_idioms,
+    unreachable_pub
+)]
 #![allow(elided_lifetimes_in_paths)]
 
 //! Various utility types and functions that are generally with Tower.
@@ -7,13 +12,15 @@
 mod boxed;
 mod call_all;
 mod either;
-pub mod layer;
 mod oneshot;
 mod optional;
 mod ready;
 mod sealed;
 mod service_fn;
 
+/// Different ways to chain service layers.
+pub mod layer;
+
 pub use crate::{
     boxed::{BoxService, UnsyncBoxService},
     call_all::{CallAll, CallAllUnordered},
diff --git a/tower-util/src/oneshot.rs b/tower-util/src/oneshot.rs
index d7d05f6..967c419 100644
--- a/tower-util/src/oneshot.rs
+++ b/tower-util/src/oneshot.rs
@@ -1,6 +1,7 @@
 use futures_util::ready;
 use pin_project::{pin_project, project};
 use std::{
+    fmt,
     future::Future,
     pin::Pin,
     task::{Context, Poll},
@@ -11,6 +12,7 @@ use tower_service::Service;
 /// is ready, and then calling `Service::call` with the request, and
 /// waiting for that `Future`.
 #[pin_project]
+#[derive(Debug)]
 pub struct Oneshot<S: Service<Req>, Req> {
     #[pin]
     state: State<S, Req>,
@@ -23,10 +25,30 @@ enum State<S: Service<Req>, Req> {
     Done,
 }
 
+impl<S, Req> fmt::Debug for State<S, Req>
+where
+    S: Service<Req> + fmt::Debug,
+    Req: fmt::Debug,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            State::NotReady(Some((s, req))) => f
+                .debug_tuple("State::NotReady")
+                .field(s)
+                .field(req)
+                .finish(),
+            State::NotReady(None) => unreachable!(),
+            State::Called(_) => f.debug_tuple("State::Called").field(&"S::Future").finish(),
+            State::Done => f.debug_tuple("State::Done").finish(),
+        }
+    }
+}
+
 impl<S, Req> Oneshot<S, Req>
 where
     S: Service<Req>,
 {
+    #[allow(missing_docs)]
     pub fn new(svc: S, req: Req) -> Self {
         Oneshot {
             state: State::NotReady(Some((svc, req))),
diff --git a/tower-util/src/optional/error.rs b/tower-util/src/optional/error.rs
index 3ed2e00..7ae14bf 100644
--- a/tower-util/src/optional/error.rs
+++ b/tower-util/src/optional/error.rs
@@ -1,5 +1,6 @@
 use std::{error, fmt};
 
+/// Error returned if the inner `Service` has not been set.
 #[derive(Debug)]
 pub struct None(());
 
diff --git a/tower-util/src/optional/future.rs b/tower-util/src/optional/future.rs
index 25d5f45..1d9024a 100644
--- a/tower-util/src/optional/future.rs
+++ b/tower-util/src/optional/future.rs
@@ -9,6 +9,7 @@ use std::{
 
 /// Response future returned by `Optional`.
 #[pin_project]
+#[derive(Debug)]
 pub struct ResponseFuture<T> {
     #[pin]
     inner: Option<T>,
diff --git a/tower-util/src/optional/mod.rs b/tower-util/src/optional/mod.rs
index d34b3b1..4b88b39 100644
--- a/tower-util/src/optional/mod.rs
+++ b/tower-util/src/optional/mod.rs
@@ -3,7 +3,9 @@
 //! See `OptionService` documentation for more details.
 //!
 
+/// Error types for `OptionalService`.
 pub mod error;
+/// Future types for `OptionalService`.
 pub mod future;
 
 use self::{error::Error, future::ResponseFuture};
@@ -13,6 +15,7 @@ use tower_service::Service;
 /// Optionally forwards requests to an inner service.
 ///
 /// If the inner service is `None`, `Error::None` is returned as the response.
+#[derive(Debug)]
 pub struct Optional<T> {
     inner: Option<T>,
 }
diff --git a/tower-util/src/ready.rs b/tower-util/src/ready.rs
index cc11628..c4e83fe 100644
--- a/tower-util/src/ready.rs
+++ b/tower-util/src/ready.rs
@@ -22,6 +22,7 @@ impl<'a, T, Request> Ready<'a, T, Request>
 where
     T: Service<Request>,
 {
+    #[allow(missing_docs)]
     pub fn new(service: &'a mut T) -> Self {
         Ready {
             inner: service,
diff --git a/tower-util/src/sealed.rs b/tower-util/src/sealed.rs
index cf4c71a..d47002e 100644
--- a/tower-util/src/sealed.rs
+++ b/tower-util/src/sealed.rs
@@ -1,1 +1,2 @@
+#[allow(unreachable_pub)]
 pub trait Sealed<T> {}
diff --git a/tower/src/builder/mod.rs b/tower/src/builder/mod.rs
index f887a8c..2281858 100644
--- a/tower/src/builder/mod.rs
+++ b/tower/src/builder/mod.rs
@@ -188,7 +188,7 @@ impl<L> ServiceBuilder<L> {
 }
 
 impl<L: fmt::Debug> fmt::Debug for ServiceBuilder<L> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_tuple("ServiceBuilder").field(&self.layer).finish()
     }
 }
diff --git a/tower/src/lib.rs b/tower/src/lib.rs
index 774e9be..6c5066e 100644
--- a/tower/src/lib.rs
+++ b/tower/src/lib.rs
@@ -2,9 +2,12 @@
 // Allows refining features in the future without breaking backwards
 // compatibility
 #![cfg(feature = "full")]
-#![deny(missing_docs, missing_debug_implementations, rust_2018_idioms)]
-#![allow(elided_lifetimes_in_paths)]
-#![cfg_attr(test, deny(warnings))]
+#![warn(
+    missing_debug_implementations,
+    missing_docs,
+    rust_2018_idioms,
+    unreachable_pub
+)]
 
 //! `fn(Request) -> Future<Response>`
 //!


Test patch:
diff --git a/ci/azure-test-stable.yml b/ci/azure-test-stable.yml
index 3aa7a74..ec01ca5 100644
--- a/ci/azure-test-stable.yml
+++ b/ci/azure-test-stable.yml
@@ -17,6 +17,7 @@ jobs:
     - script: cargo test
       env:
         CI: 'True'
+        RUSTFLAGS: '-D warnings'
       displayName: cargo test -p ${{ crate }}
       workingDirectory: $(Build.SourcesDirectory)/${{ crate }}
       condition: and(succeeded(), ne(variables['isRelease'], 'true'))
@@ -27,5 +28,6 @@ jobs:
     - script: cargo test
       env:
         CI: 'True'
+        RUSTFLAGS: '-D warnings'
       displayName: cargo test -p ${{ crate }}
       workingDirectory: $(Build.SourcesDirectory)/${{ crate }}
diff --git a/tower-test/src/lib.rs b/tower-test/src/lib.rs
index 20375b2..a6259b3 100644
--- a/tower-test/src/lib.rs
+++ b/tower-test/src/lib.rs
@@ -1,5 +1,10 @@
 #![doc(html_root_url = "https://docs.rs/tower-test/0.3.0-alpha.1")]
-#![deny(rust_2018_idioms)]
+#![warn(
+    missing_debug_implementations,
+    missing_docs,
+    rust_2018_idioms,
+    unreachable_pub
+)]
 #![allow(elided_lifetimes_in_paths)]
 
 //! Mock `Service` that can be used in tests.
diff --git a/tower-test/src/mock/error.rs b/tower-test/src/mock/error.rs
index 7005f9d..84f1815 100644
--- a/tower-test/src/mock/error.rs
+++ b/tower-test/src/mock/error.rs
@@ -4,6 +4,7 @@ use std::{error, fmt};
 
 pub(crate) type Error = Box<dyn error::Error + Send + Sync>;
 
+/// Error yielded when a mocked service does not yet accept requests.
 #[derive(Debug)]
 pub struct Closed(());
 
diff --git a/tower-test/src/mock/mod.rs b/tower-test/src/mock/mod.rs
index 1d3d8d7..cffe11d 100644
--- a/tower-test/src/mock/mod.rs
+++ b/tower-test/src/mock/mod.rs
@@ -261,11 +261,13 @@ impl<T, U> Drop for Handle<T, U> {
 // ===== impl SendResponse =====
 
 impl<T> SendResponse<T> {
+    /// Resolve the pending request future for the linked request with the given response.
     pub fn send_response(self, response: T) {
         // TODO: Should the result be dropped?
         let _ = self.tx.send(Ok(response));
     }
 
+    /// Resolve the pending request future for the linked request with the given error.
     pub fn send_error<E: Into<Error>>(self, err: E) {
         // TODO: Should the result be dropped?
         let _ = self.tx.send(Err(err.into()));