mirror of
https://github.com/openharmony/third_party_rust_http.git
synced 2026-07-19 22:53:59 -04:00
add Extensions (#40)
This commit is contained in:
committed by
Carl Lerche
parent
243508d84c
commit
ec32836f48
@@ -0,0 +1,157 @@
|
||||
use std::any::{Any, TypeId};
|
||||
use std::collections::HashMap;
|
||||
use std::hash::BuildHasherDefault;
|
||||
use std::fmt;
|
||||
|
||||
use fnv::FnvHasher;
|
||||
|
||||
type AnyMap = HashMap<TypeId, Box<Any + Send + Sync>, BuildHasherDefault<FnvHasher>>;
|
||||
|
||||
/// A type map of protocol extensions.
|
||||
///
|
||||
/// `Extensions` can be used by `Request` and `Response` to store
|
||||
/// extra data derived from the underlying protocol.
|
||||
#[derive(Default)]
|
||||
pub struct Extensions {
|
||||
map: AnyMap,
|
||||
}
|
||||
|
||||
impl Extensions {
|
||||
/// Create an empty `Extensions`.
|
||||
#[inline]
|
||||
pub fn new() -> Extensions {
|
||||
Extensions {
|
||||
map: HashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Insert a type into this `Extensions`.
|
||||
///
|
||||
/// If a extension of this type already existed, it will
|
||||
/// be returned.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use http::Extensions;
|
||||
/// let mut ext = Extensions::new();
|
||||
/// assert!(ext.insert(5i32).is_none());
|
||||
/// assert!(ext.insert(4u8).is_none());
|
||||
/// assert_eq!(ext.insert(9i32), Some(5i32));
|
||||
/// ```
|
||||
pub fn insert<T: Send + Sync + 'static>(&mut self, val: T) -> Option<T> {
|
||||
self.map.insert(TypeId::of::<T>(), Box::new(val))
|
||||
.and_then(|boxed| {
|
||||
//TODO: we can use unsafe and remove double checking the type id
|
||||
(boxed as Box<Any + 'static>)
|
||||
.downcast()
|
||||
.ok()
|
||||
.map(|boxed| *boxed)
|
||||
})
|
||||
}
|
||||
|
||||
/// Get a reference to a type previously inserted on this `Extensions`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use http::Extensions;
|
||||
/// let mut ext = Extensions::new();
|
||||
/// assert!(ext.get::<i32>().is_none());
|
||||
/// ext.insert(5i32);
|
||||
///
|
||||
/// assert_eq!(ext.get::<i32>(), Some(&5i32));
|
||||
/// ```
|
||||
pub fn get<T: Send + Sync + 'static>(&self) -> Option<&T> {
|
||||
self.map.get(&TypeId::of::<T>())
|
||||
//TODO: we can use unsafe and remove double checking the type id
|
||||
.and_then(|boxed| (&**boxed as &(Any + 'static)).downcast_ref())
|
||||
}
|
||||
|
||||
/// Get a mutable reference to a type previously inserted on this `Extensions`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use http::Extensions;
|
||||
/// let mut ext = Extensions::new();
|
||||
/// ext.insert(String::from("Hello"));
|
||||
/// ext.get_mut::<String>().unwrap().push_str(" World");
|
||||
///
|
||||
/// assert_eq!(ext.get::<String>().unwrap(), "Hello World");
|
||||
/// ```
|
||||
pub fn get_mut<T: Send + Sync + 'static>(&mut self) -> Option<&mut T> {
|
||||
self.map.get_mut(&TypeId::of::<T>())
|
||||
//TODO: we can use unsafe and remove double checking the type id
|
||||
.and_then(|boxed| (&mut **boxed as &mut (Any + 'static)).downcast_mut())
|
||||
}
|
||||
|
||||
|
||||
/// Remove a type from this `Extensions`.
|
||||
///
|
||||
/// If a extension of this type existed, it will be returned.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use http::Extensions;
|
||||
/// let mut ext = Extensions::new();
|
||||
/// ext.insert(5i32);
|
||||
/// assert_eq!(ext.remove::<i32>(), Some(5i32));
|
||||
/// assert!(ext.get::<i32>().is_none());
|
||||
/// ```
|
||||
pub fn remove<T: Send + Sync + 'static>(&mut self) -> Option<T> {
|
||||
self.map.remove(&TypeId::of::<T>())
|
||||
.and_then(|boxed| {
|
||||
//TODO: we can use unsafe and remove double checking the type id
|
||||
(boxed as Box<Any + 'static>)
|
||||
.downcast()
|
||||
.ok()
|
||||
.map(|boxed| *boxed)
|
||||
})
|
||||
}
|
||||
|
||||
/// Clear the `Extensions` of all inserted extensions.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use http::Extensions;
|
||||
/// let mut ext = Extensions::new();
|
||||
/// ext.insert(5i32);
|
||||
/// ext.clear();
|
||||
///
|
||||
/// assert!(ext.get::<i32>().is_none());
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn clear(&mut self) {
|
||||
self.map.clear();
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Extensions {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("Extensions")
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_extensions() {
|
||||
#[derive(Debug, PartialEq)]
|
||||
struct MyType(i32);
|
||||
|
||||
let mut extensions = Extensions::new();
|
||||
|
||||
extensions.insert(5i32);
|
||||
extensions.insert(MyType(10));
|
||||
|
||||
assert_eq!(extensions.get(), Some(&5i32));
|
||||
assert_eq!(extensions.get_mut(), Some(&mut 5i32));
|
||||
|
||||
assert_eq!(extensions.remove::<i32>(), Some(5i32));
|
||||
assert!(extensions.get::<i32>().is_none());
|
||||
|
||||
assert_eq!(extensions.get::<bool>(), None);
|
||||
assert_eq!(extensions.get(), Some(&MyType(10)));
|
||||
}
|
||||
+13
@@ -14,7 +14,9 @@ pub mod version;
|
||||
pub mod uri;
|
||||
|
||||
mod byte_str;
|
||||
mod extensions;
|
||||
|
||||
pub use extensions::Extensions;
|
||||
pub use header::HeaderMap;
|
||||
pub use method::Method;
|
||||
pub use request::Request;
|
||||
@@ -22,3 +24,14 @@ pub use response::Response;
|
||||
pub use status::StatusCode;
|
||||
pub use version::Version;
|
||||
pub use uri::Uri;
|
||||
|
||||
fn _assert_types() {
|
||||
fn assert_send<T: Send>() {}
|
||||
fn assert_sync<T: Sync>() {}
|
||||
|
||||
assert_send::<Request<()>>();
|
||||
assert_send::<Response<()>>();
|
||||
|
||||
assert_sync::<Request<()>>();
|
||||
assert_sync::<Response<()>>();
|
||||
}
|
||||
|
||||
+35
-5
@@ -1,9 +1,7 @@
|
||||
//! HTTP request types.
|
||||
|
||||
use Uri;
|
||||
use {Extensions, Method, Uri, Version};
|
||||
use header::{HeaderMap, HeaderValue};
|
||||
use method::Method;
|
||||
use version::Version;
|
||||
|
||||
/// Represents an HTTP request.
|
||||
///
|
||||
@@ -11,7 +9,7 @@ use version::Version;
|
||||
/// component is generic, enabling arbitrary types to represent the HTTP body.
|
||||
/// For example, the body could be `Vec<u8>`, a `Stream` of byte chunks, or a
|
||||
/// value that has been deserialized.
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Request<T> {
|
||||
head: Head,
|
||||
body: T,
|
||||
@@ -21,7 +19,7 @@ pub struct Request<T> {
|
||||
///
|
||||
/// The HTTP request head consists of a method, uri, version, and a set of
|
||||
/// header fields.
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Head {
|
||||
/// The request's method
|
||||
pub method: Method,
|
||||
@@ -35,6 +33,9 @@ pub struct Head {
|
||||
/// The request's headers
|
||||
pub headers: HeaderMap<HeaderValue>,
|
||||
|
||||
/// The request's extensions
|
||||
pub extensions: Extensions,
|
||||
|
||||
_priv: (),
|
||||
}
|
||||
|
||||
@@ -167,6 +168,35 @@ impl<T> Request<T> {
|
||||
&mut self.head.headers
|
||||
}
|
||||
|
||||
|
||||
/// Returns a reference to the associated extensions.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use http::*;
|
||||
/// let request: Request<()> = Request::default();
|
||||
/// assert!(request.extensions().get::<i32>().is_none());
|
||||
/// ```
|
||||
pub fn extensions(&self) -> &Extensions {
|
||||
&self.head.extensions
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the associated extensions.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use http::*;
|
||||
/// # use http::header::*;
|
||||
/// let mut request: Request<()> = Request::default();
|
||||
/// request.extensions_mut().insert("hello");
|
||||
/// assert_eq!(request.extensions().get(), Some(&"hello"));
|
||||
/// ```
|
||||
pub fn extensions_mut(&mut self) -> &mut Extensions {
|
||||
&mut self.head.extensions
|
||||
}
|
||||
|
||||
/// Returns a reference to the associated HTTP body.
|
||||
///
|
||||
/// # Examples
|
||||
|
||||
+34
-4
@@ -1,8 +1,7 @@
|
||||
//! HTTP response types.
|
||||
|
||||
use {Extensions, StatusCode, Version};
|
||||
use header::{HeaderMap, HeaderValue};
|
||||
use status::StatusCode;
|
||||
use version::Version;
|
||||
|
||||
/// Represents an HTTP response
|
||||
///
|
||||
@@ -10,7 +9,7 @@ use version::Version;
|
||||
/// component is generic, enabling arbitrary types to represent the HTTP body.
|
||||
/// For example, the body could be `Vec<u8>`, a `Stream` of byte chunks, or a
|
||||
/// value that has been deserialized.
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Response<T> {
|
||||
head: Head,
|
||||
body: T,
|
||||
@@ -20,7 +19,7 @@ pub struct Response<T> {
|
||||
///
|
||||
/// The HTTP response head consists of a status, version, and a set of
|
||||
/// header fields.
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Head {
|
||||
/// The response's status
|
||||
pub status: StatusCode,
|
||||
@@ -31,6 +30,9 @@ pub struct Head {
|
||||
/// The response's headers
|
||||
pub headers: HeaderMap<HeaderValue>,
|
||||
|
||||
/// The response's extensions
|
||||
pub extensions: Extensions,
|
||||
|
||||
_priv: (),
|
||||
}
|
||||
|
||||
@@ -136,6 +138,34 @@ impl<T> Response<T> {
|
||||
&mut self.head.headers
|
||||
}
|
||||
|
||||
/// Returns a reference to the associated extensions.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use http::*;
|
||||
/// let response: Response<()> = Response::default();
|
||||
/// assert!(response.extensions().get::<i32>().is_none());
|
||||
/// ```
|
||||
pub fn extensions(&self) -> &Extensions {
|
||||
&self.head.extensions
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the associated extensions.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use http::*;
|
||||
/// # use http::header::*;
|
||||
/// let mut response: Response<()> = Response::default();
|
||||
/// response.extensions_mut().insert("hello");
|
||||
/// assert_eq!(response.extensions().get(), Some(&"hello"));
|
||||
/// ```
|
||||
pub fn extensions_mut(&mut self) -> &mut Extensions {
|
||||
&mut self.head.extensions
|
||||
}
|
||||
|
||||
/// Returns a reference to the associated HTTP body.
|
||||
///
|
||||
/// # Examples
|
||||
|
||||
Reference in New Issue
Block a user