1
0
mirror of https://github.com/fafhrd91/actix-web synced 2025-01-31 11:02:08 +01:00

return option item from Extensions::insert (#1904)

This commit is contained in:
Rob Ede 2021-01-15 04:22:42 +00:00 committed by GitHub
parent b1dd8d28bc
commit f976150b67
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 82 additions and 17 deletions

View File

@ -12,6 +12,7 @@
`mime` types. [#1894] `mime` types. [#1894]
* Renamed `IntoHeaderValue::{try_into => try_into_value}` to avoid ambiguity with std * Renamed `IntoHeaderValue::{try_into => try_into_value}` to avoid ambiguity with std
`TryInto` trait. [#1894] `TryInto` trait. [#1894]
* `Extensions::insert` returns Option of replaced item. [#1904]
### Removed ### Removed
* `ResponseBuilder::set`; use `ResponseBuilder::insert_header`. [#1869] * `ResponseBuilder::set`; use `ResponseBuilder::insert_header`. [#1869]
@ -22,6 +23,7 @@
[#1869]: https://github.com/actix/actix-web/pull/1869 [#1869]: https://github.com/actix/actix-web/pull/1869
[#1894]: https://github.com/actix/actix-web/pull/1894 [#1894]: https://github.com/actix/actix-web/pull/1894
[#1904]: https://github.com/actix/actix-web/pull/1904
## 3.0.0-beta.1 - 2021-01-07 ## 3.0.0-beta.1 - 2021-01-07

View File

@ -5,7 +5,9 @@ use std::{
use ahash::AHashMap; use ahash::AHashMap;
/// A type map of request extensions. /// A type map for request extensions.
///
/// All entries into this map must be owned types (or static references).
#[derive(Default)] #[derive(Default)]
pub struct Extensions { pub struct Extensions {
/// Use FxHasher with a std HashMap with for faster /// Use FxHasher with a std HashMap with for faster
@ -14,7 +16,7 @@ pub struct Extensions {
} }
impl Extensions { impl Extensions {
/// Create an empty `Extensions`. /// Creates an empty `Extensions`.
#[inline] #[inline]
pub fn new() -> Extensions { pub fn new() -> Extensions {
Extensions { Extensions {
@ -22,43 +24,96 @@ impl Extensions {
} }
} }
/// Insert a type into this `Extensions`. /// Insert an item into the map.
/// ///
/// If a extension of this type already existed, it will /// If an item of this type was already stored, it will be replaced and returned.
/// be returned. ///
pub fn insert<T: 'static>(&mut self, val: T) { /// ```
self.map.insert(TypeId::of::<T>(), Box::new(val)); /// # use actix_http::Extensions;
/// let mut map = Extensions::new();
/// assert_eq!(map.insert(""), None);
/// assert_eq!(map.insert(1u32), None);
/// assert_eq!(map.insert(2u32), Some(1u32));
/// assert_eq!(*map.get::<u32>().unwrap(), 2u32);
/// ```
pub fn insert<T: 'static>(&mut self, val: T) -> Option<T> {
self.map
.insert(TypeId::of::<T>(), Box::new(val))
.and_then(downcast_owned)
} }
/// Check if container contains entry /// Check if map contains an item of a given type.
///
/// ```
/// # use actix_http::Extensions;
/// let mut map = Extensions::new();
/// assert!(!map.contains::<u32>());
///
/// assert_eq!(map.insert(1u32), None);
/// assert!(map.contains::<u32>());
/// ```
pub fn contains<T: 'static>(&self) -> bool { pub fn contains<T: 'static>(&self) -> bool {
self.map.contains_key(&TypeId::of::<T>()) self.map.contains_key(&TypeId::of::<T>())
} }
/// Get a reference to a type previously inserted on this `Extensions`. /// Get a reference to an item of a given type.
///
/// ```
/// # use actix_http::Extensions;
/// let mut map = Extensions::new();
/// map.insert(1u32);
/// assert_eq!(map.get::<u32>(), Some(&1u32));
/// ```
pub fn get<T: 'static>(&self) -> Option<&T> { pub fn get<T: 'static>(&self) -> Option<&T> {
self.map self.map
.get(&TypeId::of::<T>()) .get(&TypeId::of::<T>())
.and_then(|boxed| boxed.downcast_ref()) .and_then(|boxed| boxed.downcast_ref())
} }
/// Get a mutable reference to a type previously inserted on this `Extensions`. /// Get a mutable reference to an item of a given type.
///
/// ```
/// # use actix_http::Extensions;
/// let mut map = Extensions::new();
/// map.insert(1u32);
/// assert_eq!(map.get_mut::<u32>(), Some(&mut 1u32));
/// ```
pub fn get_mut<T: 'static>(&mut self) -> Option<&mut T> { pub fn get_mut<T: 'static>(&mut self) -> Option<&mut T> {
self.map self.map
.get_mut(&TypeId::of::<T>()) .get_mut(&TypeId::of::<T>())
.and_then(|boxed| boxed.downcast_mut()) .and_then(|boxed| boxed.downcast_mut())
} }
/// Remove a type from this `Extensions`. /// Remove an item from the map of a given type.
/// ///
/// If a extension of this type existed, it will be returned. /// If an item of this type was already stored, it will be returned.
///
/// ```
/// # use actix_http::Extensions;
/// let mut map = Extensions::new();
///
/// map.insert(1u32);
/// assert_eq!(map.get::<u32>(), Some(&1u32));
///
/// assert_eq!(map.remove::<u32>(), Some(1u32));
/// assert!(!map.contains::<u32>());
/// ```
pub fn remove<T: 'static>(&mut self) -> Option<T> { pub fn remove<T: 'static>(&mut self) -> Option<T> {
self.map self.map.remove(&TypeId::of::<T>()).and_then(downcast_owned)
.remove(&TypeId::of::<T>())
.and_then(|boxed| boxed.downcast().ok().map(|boxed| *boxed))
} }
/// Clear the `Extensions` of all inserted extensions. /// Clear the `Extensions` of all inserted extensions.
///
/// ```
/// # use actix_http::Extensions;
/// let mut map = Extensions::new();
///
/// map.insert(1u32);
/// assert!(map.contains::<u32>());
///
/// map.clear();
/// assert!(!map.contains::<u32>());
/// ```
#[inline] #[inline]
pub fn clear(&mut self) { pub fn clear(&mut self) {
self.map.clear(); self.map.clear();
@ -81,6 +136,10 @@ impl fmt::Debug for Extensions {
} }
} }
fn downcast_owned<T: 'static>(boxed: Box<dyn Any>) -> Option<T> {
boxed.downcast().ok().map(|boxed| *boxed)
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View File

@ -408,7 +408,9 @@ async fn test_h2_service_error() {
async fn test_h2_on_connect() { async fn test_h2_on_connect() {
let srv = test_server(move || { let srv = test_server(move || {
HttpService::build() HttpService::build()
.on_connect_ext(|_, data| data.insert(20isize)) .on_connect_ext(|_, data| {
data.insert(20isize);
})
.h2(|req: Request| { .h2(|req: Request| {
assert!(req.extensions().contains::<isize>()); assert!(req.extensions().contains::<isize>());
ok::<_, ()>(Response::Ok().finish()) ok::<_, ()>(Response::Ok().finish())

View File

@ -662,7 +662,9 @@ async fn test_h1_service_error() {
async fn test_h1_on_connect() { async fn test_h1_on_connect() {
let srv = test_server(|| { let srv = test_server(|| {
HttpService::build() HttpService::build()
.on_connect_ext(|_, data| data.insert(20isize)) .on_connect_ext(|_, data| {
data.insert(20isize);
})
.h1(|req: Request| { .h1(|req: Request| {
assert!(req.extensions().contains::<isize>()); assert!(req.extensions().contains::<isize>());
future::ok::<_, ()>(Response::Ok().finish()) future::ok::<_, ()>(Response::Ok().finish())