mirror of
https://github.com/actix/actix-web.git
synced 2024-12-30 12:00:38 +00:00
Make web::Path a tuple struct with a public inner value (#1594)
Co-authored-by: Rob Ede <robjtede@icloud.com>
This commit is contained in:
parent
43c362779d
commit
f8d5ad6b53
5 changed files with 55 additions and 33 deletions
|
@ -4,10 +4,13 @@
|
|||
### Changed
|
||||
* `PayloadConfig` is now also considered in `Bytes` and `String` extractors when set
|
||||
using `App::data`. [#1610]
|
||||
* `web::Path` now has a public representation: `web::Path(pub T)` that enables
|
||||
destructuring. [#1594]
|
||||
|
||||
### Fixed
|
||||
* Memory leak of app data in pooled requests. [#1609]
|
||||
|
||||
[#1594]: https://github.com/actix/actix-web/pull/1594
|
||||
[#1609]: https://github.com/actix/actix-web/pull/1609
|
||||
[#1610]: https://github.com/actix/actix-web/pull/1610
|
||||
|
||||
|
|
20
MIGRATION.md
20
MIGRATION.md
|
@ -12,6 +12,26 @@
|
|||
* `BodySize::Sized64` variant has been removed. `BodySize::Sized` now receives a
|
||||
`u64` instead of a `usize`.
|
||||
|
||||
* Code that was using `path.<index>` to access a `web::Path<(A, B, C)>`s elements now needs to use
|
||||
destructuring or `.into_inner()`. For example:
|
||||
|
||||
```rust
|
||||
// Previously:
|
||||
async fn some_route(path: web::Path<(String, String)>) -> String {
|
||||
format!("Hello, {} {}", path.0, path.1)
|
||||
}
|
||||
|
||||
// Now (this also worked before):
|
||||
async fn some_route(path: web::Path<(String, String)>) -> String {
|
||||
let (first_name, last_name) = path.into_inner();
|
||||
format!("Hello, {} {}", first_name, last_name)
|
||||
}
|
||||
// Or (this wasn't previously supported):
|
||||
async fn some_route(web::Path((first_name, last_name)): web::Path<(String, String)>) -> String {
|
||||
format!("Hello, {} {}", first_name, last_name)
|
||||
}
|
||||
```
|
||||
|
||||
## 2.0.0
|
||||
|
||||
* `HttpServer::start()` renamed to `HttpServer::run()`. It also possible to
|
||||
|
|
|
@ -61,8 +61,8 @@ Code:
|
|||
use actix_web::{get, web, App, HttpServer, Responder};
|
||||
|
||||
#[get("/{id}/{name}/index.html")]
|
||||
async fn index(info: web::Path<(u32, String)>) -> impl Responder {
|
||||
format!("Hello {}! id:{}", info.1, info.0)
|
||||
async fn index(web::Path((id, name)): web::Path<(u32, String)>) -> impl Responder {
|
||||
format!("Hello {}! id:{}", name, id)
|
||||
}
|
||||
|
||||
#[actix_web::main]
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
//! use actix_web::{get, web, App, HttpServer, Responder};
|
||||
//!
|
||||
//! #[get("/{id}/{name}/index.html")]
|
||||
//! async fn index(info: web::Path<(u32, String)>) -> impl Responder {
|
||||
//! format!("Hello {}! id:{}", info.1, info.0)
|
||||
//! async fn index(web::Path((id, name)): web::Path<(u32, String)>) -> impl Responder {
|
||||
//! format!("Hello {}! id:{}", name, id)
|
||||
//! }
|
||||
//!
|
||||
//! #[actix_web::main]
|
||||
|
|
|
@ -25,8 +25,8 @@ use crate::FromRequest;
|
|||
/// /// extract path info from "/{username}/{count}/index.html" url
|
||||
/// /// {username} - deserializes to a String
|
||||
/// /// {count} - - deserializes to a u32
|
||||
/// async fn index(info: web::Path<(String, u32)>) -> String {
|
||||
/// format!("Welcome {}! {}", info.0, info.1)
|
||||
/// async fn index(web::Path((username, count)): web::Path<(String, u32)>) -> String {
|
||||
/// format!("Welcome {}! {}", username, count)
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
|
@ -61,20 +61,18 @@ use crate::FromRequest;
|
|||
/// );
|
||||
/// }
|
||||
/// ```
|
||||
pub struct Path<T> {
|
||||
inner: T,
|
||||
}
|
||||
pub struct Path<T>(pub T);
|
||||
|
||||
impl<T> Path<T> {
|
||||
/// Deconstruct to an inner value
|
||||
pub fn into_inner(self) -> T {
|
||||
self.inner
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AsRef<T> for Path<T> {
|
||||
fn as_ref(&self) -> &T {
|
||||
&self.inner
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,31 +80,31 @@ impl<T> ops::Deref for Path<T> {
|
|||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
&self.inner
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ops::DerefMut for Path<T> {
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
&mut self.inner
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for Path<T> {
|
||||
fn from(inner: T) -> Path<T> {
|
||||
Path { inner }
|
||||
Path(inner)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Debug> fmt::Debug for Path<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.inner.fmt(f)
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Display> fmt::Display for Path<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.inner.fmt(f)
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -120,8 +118,8 @@ impl<T: fmt::Display> fmt::Display for Path<T> {
|
|||
/// /// extract path info from "/{username}/{count}/index.html" url
|
||||
/// /// {username} - deserializes to a String
|
||||
/// /// {count} - - deserializes to a u32
|
||||
/// async fn index(info: web::Path<(String, u32)>) -> String {
|
||||
/// format!("Welcome {}! {}", info.0, info.1)
|
||||
/// async fn index(web::Path((username, count)): web::Path<(String, u32)>) -> String {
|
||||
/// format!("Welcome {}! {}", username, count)
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
|
@ -173,7 +171,7 @@ where
|
|||
|
||||
ready(
|
||||
de::Deserialize::deserialize(PathDeserializer::new(req.match_info()))
|
||||
.map(|inner| Path { inner })
|
||||
.map(Path)
|
||||
.map_err(move |e| {
|
||||
log::debug!(
|
||||
"Failed during Path extractor deserialization. \
|
||||
|
@ -290,21 +288,22 @@ mod tests {
|
|||
resource.match_path(req.match_info_mut());
|
||||
|
||||
let (req, mut pl) = req.into_parts();
|
||||
let res = <(Path<(String, String)>,)>::from_request(&req, &mut pl)
|
||||
let (Path(res),) = <(Path<(String, String)>,)>::from_request(&req, &mut pl)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!((res.0).0, "name");
|
||||
assert_eq!((res.0).1, "user1");
|
||||
assert_eq!(res.0, "name");
|
||||
assert_eq!(res.1, "user1");
|
||||
|
||||
let res = <(Path<(String, String)>, Path<(String, String)>)>::from_request(
|
||||
&req, &mut pl,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!((res.0).0, "name");
|
||||
assert_eq!((res.0).1, "user1");
|
||||
assert_eq!((res.1).0, "name");
|
||||
assert_eq!((res.1).1, "user1");
|
||||
let (Path(a), Path(b)) =
|
||||
<(Path<(String, String)>, Path<(String, String)>)>::from_request(
|
||||
&req, &mut pl,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(a.0, "name");
|
||||
assert_eq!(a.1, "user1");
|
||||
assert_eq!(b.0, "name");
|
||||
assert_eq!(b.1, "user1");
|
||||
|
||||
let () = <()>::from_request(&req, &mut pl).await.unwrap();
|
||||
}
|
||||
|
@ -329,7 +328,7 @@ mod tests {
|
|||
let s = s.into_inner();
|
||||
assert_eq!(s.value, "user2");
|
||||
|
||||
let s = Path::<(String, String)>::from_request(&req, &mut pl)
|
||||
let Path(s) = Path::<(String, String)>::from_request(&req, &mut pl)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(s.0, "name");
|
||||
|
@ -344,7 +343,7 @@ mod tests {
|
|||
assert_eq!(s.as_ref().key, "name");
|
||||
assert_eq!(s.value, 32);
|
||||
|
||||
let s = Path::<(String, u8)>::from_request(&req, &mut pl)
|
||||
let Path(s) = Path::<(String, u8)>::from_request(&req, &mut pl)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(s.0, "name");
|
||||
|
|
Loading…
Reference in a new issue