mirror of
https://github.com/tokio-rs/axum.git
synced 2026-09-02 00:00:22 +02:00
#[must_use] all the things! (#1809)
This commit is contained in:
@@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
- None.
|
- **fixed:** Add `#[must_use]` attributes to types that do nothing unless used ([#1809])
|
||||||
|
|
||||||
|
[#1809]: https://github.com/tokio-rs/axum/pull/1809
|
||||||
|
|
||||||
# 0.3.2 (20. January, 2023)
|
# 0.3.2 (20. January, 2023)
|
||||||
|
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ use tower_layer::Layer;
|
|||||||
/// [`RequestExt::with_limited_body`]: crate::RequestExt::with_limited_body
|
/// [`RequestExt::with_limited_body`]: crate::RequestExt::with_limited_body
|
||||||
/// [`RequestExt::into_limited_body`]: crate::RequestExt::into_limited_body
|
/// [`RequestExt::into_limited_body`]: crate::RequestExt::into_limited_body
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
#[must_use]
|
||||||
pub struct DefaultBodyLimit {
|
pub struct DefaultBodyLimit {
|
||||||
kind: DefaultBodyLimitKind,
|
kind: DefaultBodyLimitKind,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ use std::fmt;
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
#[must_use]
|
||||||
pub struct AppendHeaders<I>(pub I);
|
pub struct AppendHeaders<I>(pub I);
|
||||||
|
|
||||||
impl<I, K, V> IntoResponse for AppendHeaders<I>
|
impl<I, K, V> IntoResponse for AppendHeaders<I>
|
||||||
|
|||||||
@@ -9,11 +9,13 @@ and this project adheres to [Semantic Versioning].
|
|||||||
|
|
||||||
- **added:** Add `Multipart`. This is similar to `axum::extract::Multipart`
|
- **added:** Add `Multipart`. This is similar to `axum::extract::Multipart`
|
||||||
except that it enforces field exclusivity at runtime instead of compile time,
|
except that it enforces field exclusivity at runtime instead of compile time,
|
||||||
as this improves usability.
|
as this improves usability ([#1692])
|
||||||
|
|
||||||
- **added:** Implement `Clone` for `CookieJar`, `PrivateCookieJar` and `SignedCookieJar` ([#1808])
|
- **added:** Implement `Clone` for `CookieJar`, `PrivateCookieJar` and `SignedCookieJar` ([#1808])
|
||||||
|
- **fixed:** Add `#[must_use]` attributes to types that do nothing unless used ([#1809])
|
||||||
|
|
||||||
|
[#1692]: https://github.com/tokio-rs/axum/pull/1692
|
||||||
[#1808]: https://github.com/tokio-rs/axum/pull/1808
|
[#1808]: https://github.com/tokio-rs/axum/pull/1808
|
||||||
|
[#1809]: https://github.com/tokio-rs/axum/pull/1809
|
||||||
|
|
||||||
# 0.6.0 (24. February, 2022)
|
# 0.6.0 (24. February, 2022)
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ pin_project! {
|
|||||||
/// ```
|
/// ```
|
||||||
#[cfg(feature = "async-read-body")]
|
#[cfg(feature = "async-read-body")]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
#[must_use]
|
||||||
pub struct AsyncReadBody<R> {
|
pub struct AsyncReadBody<R> {
|
||||||
#[pin]
|
#[pin]
|
||||||
read: StreamBody<ReaderStream<R>>,
|
read: StreamBody<ReaderStream<R>>,
|
||||||
|
|||||||
@@ -108,6 +108,7 @@ use tower_service::Service;
|
|||||||
///
|
///
|
||||||
/// See the [module docs](self) for examples.
|
/// See the [module docs](self) for examples.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
#[must_use]
|
||||||
pub enum Either<E1, E2> {
|
pub enum Either<E1, E2> {
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
E1(E1),
|
E1(E1),
|
||||||
@@ -119,6 +120,7 @@ pub enum Either<E1, E2> {
|
|||||||
///
|
///
|
||||||
/// See the [module docs](self) for examples.
|
/// See the [module docs](self) for examples.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
#[must_use]
|
||||||
pub enum Either3<E1, E2, E3> {
|
pub enum Either3<E1, E2, E3> {
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
E1(E1),
|
E1(E1),
|
||||||
@@ -132,6 +134,7 @@ pub enum Either3<E1, E2, E3> {
|
|||||||
///
|
///
|
||||||
/// See the [module docs](self) for examples.
|
/// See the [module docs](self) for examples.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
#[must_use]
|
||||||
pub enum Either4<E1, E2, E3, E4> {
|
pub enum Either4<E1, E2, E3, E4> {
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
E1(E1),
|
E1(E1),
|
||||||
@@ -147,6 +150,7 @@ pub enum Either4<E1, E2, E3, E4> {
|
|||||||
///
|
///
|
||||||
/// See the [module docs](self) for examples.
|
/// See the [module docs](self) for examples.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
#[must_use]
|
||||||
pub enum Either5<E1, E2, E3, E4, E5> {
|
pub enum Either5<E1, E2, E3, E4, E5> {
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
E1(E1),
|
E1(E1),
|
||||||
@@ -164,6 +168,7 @@ pub enum Either5<E1, E2, E3, E4, E5> {
|
|||||||
///
|
///
|
||||||
/// See the [module docs](self) for examples.
|
/// See the [module docs](self) for examples.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
#[must_use]
|
||||||
pub enum Either6<E1, E2, E3, E4, E5, E6> {
|
pub enum Either6<E1, E2, E3, E4, E5, E6> {
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
E1(E1),
|
E1(E1),
|
||||||
@@ -183,6 +188,7 @@ pub enum Either6<E1, E2, E3, E4, E5, E6> {
|
|||||||
///
|
///
|
||||||
/// See the [module docs](self) for examples.
|
/// See the [module docs](self) for examples.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
#[must_use]
|
||||||
pub enum Either7<E1, E2, E3, E4, E5, E6, E7> {
|
pub enum Either7<E1, E2, E3, E4, E5, E6, E7> {
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
E1(E1),
|
E1(E1),
|
||||||
@@ -204,6 +210,7 @@ pub enum Either7<E1, E2, E3, E4, E5, E6, E7> {
|
|||||||
///
|
///
|
||||||
/// See the [module docs](self) for examples.
|
/// See the [module docs](self) for examples.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
#[must_use]
|
||||||
pub enum Either8<E1, E2, E3, E4, E5, E6, E7, E8> {
|
pub enum Either8<E1, E2, E3, E4, E5, E6, E7, E8> {
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
E1(E1),
|
E1(E1),
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ pin_project! {
|
|||||||
/// ```
|
/// ```
|
||||||
// we use `AsExtractor` as the default because you're more likely to name this type if its used
|
// we use `AsExtractor` as the default because you're more likely to name this type if its used
|
||||||
// as an extractor
|
// as an extractor
|
||||||
|
#[must_use]
|
||||||
pub struct JsonLines<S, T = AsExtractor> {
|
pub struct JsonLines<S, T = AsExtractor> {
|
||||||
#[pin]
|
#[pin]
|
||||||
inner: Inner<S>,
|
inner: Inner<S>,
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ use std::ops::{Deref, DerefMut};
|
|||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "protobuf")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "protobuf")))]
|
||||||
|
#[must_use]
|
||||||
pub struct Protobuf<T>(pub T);
|
pub struct Protobuf<T>(pub T);
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ use serde::Serialize;
|
|||||||
/// ```
|
/// ```
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "erased-json")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "erased-json")))]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
#[must_use]
|
||||||
pub struct ErasedJson(serde_json::Result<Bytes>);
|
pub struct ErasedJson(serde_json::Result<Bytes>);
|
||||||
|
|
||||||
impl ErasedJson {
|
impl ErasedJson {
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ use axum::{
|
|||||||
/// # let _: Router = app;
|
/// # let _: Router = app;
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
#[must_use]
|
||||||
pub struct Resource<S = (), B = Body> {
|
pub struct Resource<S = (), B = Body> {
|
||||||
pub(crate) name: String,
|
pub(crate) name: String,
|
||||||
pub(crate) router: Router<S, B>,
|
pub(crate) router: Router<S, B>,
|
||||||
|
|||||||
+3
-2
@@ -7,12 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
|
- **fixed:** Add `#[must_use]` attributes to types that do nothing unless used ([#1809])
|
||||||
- **fixed:** Add `#[must_use]` to `WebSocketUpgrade::on_upgrade` ([#1801])
|
- **fixed:** Add `#[must_use]` to `WebSocketUpgrade::on_upgrade` ([#1801])
|
||||||
- **fixed:** Fix routing issues when loading a `Router` via a dynamic library ([#1806])
|
- **fixed:** Fix routing issues when loading a `Router` via a dynamic library ([#1806])
|
||||||
|
|
||||||
[#1806]: https://github.com/tokio-rs/axum/pull/1806
|
|
||||||
|
|
||||||
[#1801]: https://github.com/tokio-rs/axum/pull/1801
|
[#1801]: https://github.com/tokio-rs/axum/pull/1801
|
||||||
|
[#1806]: https://github.com/tokio-rs/axum/pull/1806
|
||||||
|
[#1809]: https://github.com/tokio-rs/axum/pull/1809
|
||||||
|
|
||||||
# 0.6.9 (24. February, 2023)
|
# 0.6.9 (24. February, 2023)
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ pin_project! {
|
|||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// [`Stream`]: futures_util::stream::Stream
|
/// [`Stream`]: futures_util::stream::Stream
|
||||||
|
#[must_use]
|
||||||
pub struct StreamBody<S> {
|
pub struct StreamBody<S> {
|
||||||
#[pin]
|
#[pin]
|
||||||
stream: SyncWrapper<S>,
|
stream: SyncWrapper<S>,
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ use tower_service::Service;
|
|||||||
/// struct Foo(&'static str);
|
/// struct Foo(&'static str);
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
|
#[must_use]
|
||||||
pub struct Extension<T>(pub T);
|
pub struct Extension<T>(pub T);
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ use std::ops::Deref;
|
|||||||
/// [`Multipart`]: crate::extract::Multipart
|
/// [`Multipart`]: crate::extract::Multipart
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "form")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "form")))]
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
|
#[must_use]
|
||||||
pub struct Form<T>(pub T);
|
pub struct Form<T>(pub T);
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ use std::ops::{Deref, DerefMut};
|
|||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
|
||||||
|
#[must_use]
|
||||||
pub struct Json<T>(pub T);
|
pub struct Json<T>(pub T);
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
|||||||
@@ -110,6 +110,7 @@ pub fn from_extractor_with_state<E, S>(state: S) -> FromExtractorLayer<E, S> {
|
|||||||
/// See [`from_extractor`] for more details.
|
/// See [`from_extractor`] for more details.
|
||||||
///
|
///
|
||||||
/// [`Layer`]: tower::Layer
|
/// [`Layer`]: tower::Layer
|
||||||
|
#[must_use]
|
||||||
pub struct FromExtractorLayer<E, S> {
|
pub struct FromExtractorLayer<E, S> {
|
||||||
state: S,
|
state: S,
|
||||||
_marker: PhantomData<fn() -> E>,
|
_marker: PhantomData<fn() -> E>,
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ pub fn from_fn_with_state<F, S, T>(state: S, f: F) -> FromFnLayer<F, S, T> {
|
|||||||
/// [`tower::Layer`] is used to apply middleware to [`Router`](crate::Router)'s.
|
/// [`tower::Layer`] is used to apply middleware to [`Router`](crate::Router)'s.
|
||||||
///
|
///
|
||||||
/// Created with [`from_fn`]. See that function for more details.
|
/// Created with [`from_fn`]. See that function for more details.
|
||||||
|
#[must_use]
|
||||||
pub struct FromFnLayer<F, S, T> {
|
pub struct FromFnLayer<F, S, T> {
|
||||||
f: F,
|
f: F,
|
||||||
state: S,
|
state: S,
|
||||||
|
|||||||
@@ -165,6 +165,7 @@ pub fn map_request_with_state<F, S, T>(state: S, f: F) -> MapRequestLayer<F, S,
|
|||||||
/// A [`tower::Layer`] from an async function that transforms a request.
|
/// A [`tower::Layer`] from an async function that transforms a request.
|
||||||
///
|
///
|
||||||
/// Created with [`map_request`]. See that function for more details.
|
/// Created with [`map_request`]. See that function for more details.
|
||||||
|
#[must_use]
|
||||||
pub struct MapRequestLayer<F, S, T> {
|
pub struct MapRequestLayer<F, S, T> {
|
||||||
f: F,
|
f: F,
|
||||||
state: S,
|
state: S,
|
||||||
|
|||||||
@@ -149,6 +149,7 @@ pub fn map_response_with_state<F, S, T>(state: S, f: F) -> MapResponseLayer<F, S
|
|||||||
/// A [`tower::Layer`] from an async function that transforms a response.
|
/// A [`tower::Layer`] from an async function that transforms a response.
|
||||||
///
|
///
|
||||||
/// Created with [`map_response`]. See that function for more details.
|
/// Created with [`map_response`]. See that function for more details.
|
||||||
|
#[must_use]
|
||||||
pub struct MapResponseLayer<F, S, T> {
|
pub struct MapResponseLayer<F, S, T> {
|
||||||
f: F,
|
f: F,
|
||||||
state: S,
|
state: S,
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ pub use sse::Sse;
|
|||||||
///
|
///
|
||||||
/// Will automatically get `Content-Type: text/html`.
|
/// Will automatically get `Content-Type: text/html`.
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[must_use]
|
||||||
pub struct Html<T>(pub T);
|
pub struct Html<T>(pub T);
|
||||||
|
|
||||||
impl<T> IntoResponse for Html<T>
|
impl<T> IntoResponse for Html<T>
|
||||||
@@ -98,7 +99,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Router::<(), Body>::new()
|
_ = Router::<(), Body>::new()
|
||||||
.route("/", get(impl_trait_ok))
|
.route("/", get(impl_trait_ok))
|
||||||
.route("/", get(impl_trait_err))
|
.route("/", get(impl_trait_err))
|
||||||
.route("/", get(impl_trait_both))
|
.route("/", get(impl_trait_both))
|
||||||
@@ -208,7 +209,7 @@ mod tests {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Router::<(), Body>::new()
|
_ = Router::<(), Body>::new()
|
||||||
.route("/", get(status))
|
.route("/", get(status))
|
||||||
.route("/", get(status_headermap))
|
.route("/", get(status_headermap))
|
||||||
.route("/", get(status_header_array))
|
.route("/", get(status_header_array))
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ use tokio::time::Sleep;
|
|||||||
|
|
||||||
/// An SSE response
|
/// An SSE response
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
#[must_use]
|
||||||
pub struct Sse<S> {
|
pub struct Sse<S> {
|
||||||
stream: S,
|
stream: S,
|
||||||
keep_alive: Option<KeepAlive>,
|
keep_alive: Option<KeepAlive>,
|
||||||
@@ -163,6 +164,7 @@ where
|
|||||||
|
|
||||||
/// Server-sent event
|
/// Server-sent event
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Debug, Default, Clone)]
|
||||||
|
#[must_use]
|
||||||
pub struct Event {
|
pub struct Event {
|
||||||
buffer: BytesMut,
|
buffer: BytesMut,
|
||||||
flags: EventFlags,
|
flags: EventFlags,
|
||||||
@@ -383,6 +385,7 @@ bitflags::bitflags! {
|
|||||||
/// Configure the interval between keep-alive messages, the content
|
/// Configure the interval between keep-alive messages, the content
|
||||||
/// of each message, and the associated stream.
|
/// of each message, and the associated stream.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
#[must_use]
|
||||||
pub struct KeepAlive {
|
pub struct KeepAlive {
|
||||||
event: Bytes,
|
event: Bytes,
|
||||||
max_interval: Duration,
|
max_interval: Duration,
|
||||||
|
|||||||
@@ -513,6 +513,7 @@ where
|
|||||||
/// S: Service<Request<Body>>,
|
/// S: Service<Request<Body>>,
|
||||||
/// {}
|
/// {}
|
||||||
/// ```
|
/// ```
|
||||||
|
#[must_use]
|
||||||
pub struct MethodRouter<S = (), B = Body, E = Infallible> {
|
pub struct MethodRouter<S = (), B = Body, E = Infallible> {
|
||||||
get: MethodEndpoint<S, B, E>,
|
get: MethodEndpoint<S, B, E>,
|
||||||
head: MethodEndpoint<S, B, E>,
|
head: MethodEndpoint<S, B, E>,
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ pub use self::method_routing::{
|
|||||||
pub(crate) struct RouteId(u32);
|
pub(crate) struct RouteId(u32);
|
||||||
|
|
||||||
/// The router type for composing handlers and services.
|
/// The router type for composing handlers and services.
|
||||||
|
#[must_use]
|
||||||
pub struct Router<S = (), B = Body> {
|
pub struct Router<S = (), B = Body> {
|
||||||
routes: HashMap<RouteId, Endpoint<S, B>>,
|
routes: HashMap<RouteId, Endpoint<S, B>>,
|
||||||
node: Arc<Node>,
|
node: Arc<Node>,
|
||||||
|
|||||||
@@ -522,7 +522,7 @@ fn routes_with_overlapping_method_routes() {
|
|||||||
fn merging_with_overlapping_method_routes() {
|
fn merging_with_overlapping_method_routes() {
|
||||||
async fn handler() {}
|
async fn handler() {}
|
||||||
let app: Router = Router::new().route("/foo/bar", get(handler));
|
let app: Router = Router::new().route("/foo/bar", get(handler));
|
||||||
app.clone().merge(app);
|
_ = app.clone().merge(app);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[crate::test]
|
#[crate::test]
|
||||||
|
|||||||
@@ -257,7 +257,7 @@ async fn multiple_top_level_nests() {
|
|||||||
#[crate::test]
|
#[crate::test]
|
||||||
#[should_panic(expected = "Invalid route: nested routes cannot contain wildcards (*)")]
|
#[should_panic(expected = "Invalid route: nested routes cannot contain wildcards (*)")]
|
||||||
async fn nest_cannot_contain_wildcards() {
|
async fn nest_cannot_contain_wildcards() {
|
||||||
Router::<(), Body>::new().nest("/one/*rest", Router::new());
|
_ = Router::<(), Body>::new().nest("/one/*rest", Router::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[crate::test]
|
#[crate::test]
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ use std::{convert::Infallible, ops::Deref};
|
|||||||
/// ```
|
/// ```
|
||||||
#[cfg(feature = "headers")]
|
#[cfg(feature = "headers")]
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
#[must_use]
|
||||||
pub struct TypedHeader<T>(pub T);
|
pub struct TypedHeader<T>(pub T);
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
|||||||
Reference in New Issue
Block a user