Merge pull request #563 from hyperium/assert-sync
feat(client): impl Sync for Client
This commit is contained in:
		| @@ -20,7 +20,7 @@ fn main() { | |||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     let mut client = Client::new(); |     let client = Client::new(); | ||||||
|  |  | ||||||
|     let mut res = client.get(&*url) |     let mut res = client.get(&*url) | ||||||
|         .header(Connection::close()) |         .header(Connection::close()) | ||||||
|   | |||||||
| @@ -21,7 +21,7 @@ fn main() { | |||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     let mut client = Client::with_protocol(h2::new_protocol()); |     let client = Client::with_protocol(h2::new_protocol()); | ||||||
|  |  | ||||||
|     // `Connection: Close` is not a valid header for HTTP/2, but the client handles it gracefully. |     // `Connection: Close` is not a valid header for HTTP/2, but the client handles it gracefully. | ||||||
|     let mut res = client.get(&*url) |     let mut res = client.get(&*url) | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ | |||||||
| //! | //! | ||||||
| //! ```no_run | //! ```no_run | ||||||
| //! # use hyper::Client; | //! # use hyper::Client; | ||||||
| //! let mut client = Client::new(); | //! let client = Client::new(); | ||||||
| //! | //! | ||||||
| //! let res = client.get("http://example.domain").send().unwrap(); | //! let res = client.get("http://example.domain").send().unwrap(); | ||||||
| //! assert_eq!(res.status, hyper::Ok); | //! assert_eq!(res.status, hyper::Ok); | ||||||
| @@ -23,7 +23,7 @@ | |||||||
| //! | //! | ||||||
| //! ```no_run | //! ```no_run | ||||||
| //! # use hyper::Client; | //! # use hyper::Client; | ||||||
| //! let mut client = Client::new(); | //! let client = Client::new(); | ||||||
| //! | //! | ||||||
| //! let res = client.post("http://example.domain") | //! let res = client.post("http://example.domain") | ||||||
| //!     .body("foo=bar") | //!     .body("foo=bar") | ||||||
| @@ -31,6 +31,30 @@ | |||||||
| //!     .unwrap(); | //!     .unwrap(); | ||||||
| //! assert_eq!(res.status, hyper::Ok); | //! assert_eq!(res.status, hyper::Ok); | ||||||
| //! ``` | //! ``` | ||||||
|  | //! | ||||||
|  | //! # Sync | ||||||
|  | //! | ||||||
|  | //! The `Client` implements `Sync`, so you can share it among multiple threads | ||||||
|  | //! and make multiple requests simultaneously. | ||||||
|  | //! | ||||||
|  | //! ```no_run | ||||||
|  | //! # use hyper::Client; | ||||||
|  | //! use std::sync::Arc; | ||||||
|  | //! use std::thread; | ||||||
|  | //! | ||||||
|  | //! // Note: an Arc is used here because `thread::spawn` creates threads that  | ||||||
|  | //! // can outlive the main thread, so we must use reference counting to keep | ||||||
|  | //! // the Client alive long enough. Scoped threads could skip the Arc. | ||||||
|  | //! let client = Arc::new(Client::new()); | ||||||
|  | //! let clone1 = client.clone(); | ||||||
|  | //! let clone2 = client.clone(); | ||||||
|  | //! thread::spawn(move || { | ||||||
|  | //!     clone1.get("http://example.domain").send().unwrap(); | ||||||
|  | //! }); | ||||||
|  | //! thread::spawn(move || { | ||||||
|  | //!     clone2.post("http://example.domain/post").body("foo=bar").send().unwrap(); | ||||||
|  | //! }); | ||||||
|  | //! ``` | ||||||
| use std::default::Default; | use std::default::Default; | ||||||
| use std::io::{self, copy, Read}; | use std::io::{self, copy, Read}; | ||||||
| use std::iter::Extend; | use std::iter::Extend; | ||||||
| @@ -61,7 +85,7 @@ use http::h1::Http11Protocol; | |||||||
| /// | /// | ||||||
| /// Clients can handle things such as: redirect policy, connection pooling. | /// Clients can handle things such as: redirect policy, connection pooling. | ||||||
| pub struct Client { | pub struct Client { | ||||||
|     protocol: Box<Protocol + Send>, |     protocol: Box<Protocol + Send + Sync>, | ||||||
|     redirect_policy: RedirectPolicy, |     redirect_policy: RedirectPolicy, | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -79,12 +103,12 @@ impl Client { | |||||||
|  |  | ||||||
|     /// Create a new client with a specific connector. |     /// Create a new client with a specific connector. | ||||||
|     pub fn with_connector<C, S>(connector: C) -> Client |     pub fn with_connector<C, S>(connector: C) -> Client | ||||||
|     where C: NetworkConnector<Stream=S> + Send + 'static, S: NetworkStream + Send { |     where C: NetworkConnector<Stream=S> + Send + Sync + 'static, S: NetworkStream + Send { | ||||||
|         Client::with_protocol(Http11Protocol::with_connector(connector)) |         Client::with_protocol(Http11Protocol::with_connector(connector)) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Create a new client with a specific `Protocol`. |     /// Create a new client with a specific `Protocol`. | ||||||
|     pub fn with_protocol<P: Protocol + Send + 'static>(protocol: P) -> Client { |     pub fn with_protocol<P: Protocol + Send + Sync + 'static>(protocol: P) -> Client { | ||||||
|         Client { |         Client { | ||||||
|             protocol: Box::new(protocol), |             protocol: Box::new(protocol), | ||||||
|             redirect_policy: Default::default() |             redirect_policy: Default::default() | ||||||
| @@ -102,33 +126,33 @@ impl Client { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Build a Get request. |     /// Build a Get request. | ||||||
|     pub fn get<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U> { |     pub fn get<U: IntoUrl>(&self, url: U) -> RequestBuilder<U> { | ||||||
|         self.request(Method::Get, url) |         self.request(Method::Get, url) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Build a Head request. |     /// Build a Head request. | ||||||
|     pub fn head<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U> { |     pub fn head<U: IntoUrl>(&self, url: U) -> RequestBuilder<U> { | ||||||
|         self.request(Method::Head, url) |         self.request(Method::Head, url) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Build a Post request. |     /// Build a Post request. | ||||||
|     pub fn post<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U> { |     pub fn post<U: IntoUrl>(&self, url: U) -> RequestBuilder<U> { | ||||||
|         self.request(Method::Post, url) |         self.request(Method::Post, url) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Build a Put request. |     /// Build a Put request. | ||||||
|     pub fn put<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U> { |     pub fn put<U: IntoUrl>(&self, url: U) -> RequestBuilder<U> { | ||||||
|         self.request(Method::Put, url) |         self.request(Method::Put, url) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /// Build a Delete request. |     /// Build a Delete request. | ||||||
|     pub fn delete<U: IntoUrl>(&mut self, url: U) -> RequestBuilder<U> { |     pub fn delete<U: IntoUrl>(&self, url: U) -> RequestBuilder<U> { | ||||||
|         self.request(Method::Delete, url) |         self.request(Method::Delete, url) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|     /// Build a new request using this Client. |     /// Build a new request using this Client. | ||||||
|     pub fn request<U: IntoUrl>(&mut self, method: Method, url: U) -> RequestBuilder<U> { |     pub fn request<U: IntoUrl>(&self, method: Method, url: U) -> RequestBuilder<U> { | ||||||
|         RequestBuilder { |         RequestBuilder { | ||||||
|             client: self, |             client: self, | ||||||
|             method: method, |             method: method, | ||||||
|   | |||||||
| @@ -275,7 +275,7 @@ impl Http11Protocol { | |||||||
|     /// Creates a new `Http11Protocol` instance that will use the given `NetworkConnector` for |     /// Creates a new `Http11Protocol` instance that will use the given `NetworkConnector` for | ||||||
|     /// establishing HTTP connections. |     /// establishing HTTP connections. | ||||||
|     pub fn with_connector<C, S>(c: C) -> Http11Protocol |     pub fn with_connector<C, S>(c: C) -> Http11Protocol | ||||||
|             where C: NetworkConnector<Stream=S> + Send + 'static, |             where C: NetworkConnector<Stream=S> + Send + Sync + 'static, | ||||||
|                   S: NetworkStream + Send { |                   S: NetworkStream + Send { | ||||||
|         Http11Protocol { |         Http11Protocol { | ||||||
|             connector: Connector(Box::new(ConnAdapter(c))), |             connector: Connector(Box::new(ConnAdapter(c))), | ||||||
| @@ -283,9 +283,9 @@ impl Http11Protocol { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| struct ConnAdapter<C: NetworkConnector + Send>(C); | struct ConnAdapter<C: NetworkConnector + Send + Sync>(C); | ||||||
|  |  | ||||||
| impl<C: NetworkConnector<Stream=S> + Send, S: NetworkStream + Send> NetworkConnector for ConnAdapter<C> { | impl<C: NetworkConnector<Stream=S> + Send + Sync, S: NetworkStream + Send> NetworkConnector for ConnAdapter<C> { | ||||||
|     type Stream = Box<NetworkStream + Send>; |     type Stream = Box<NetworkStream + Send>; | ||||||
|     #[inline] |     #[inline] | ||||||
|     fn connect(&self, host: &str, port: u16, scheme: &str) |     fn connect(&self, host: &str, port: u16, scheme: &str) | ||||||
| @@ -298,7 +298,7 @@ impl<C: NetworkConnector<Stream=S> + Send, S: NetworkStream + Send> NetworkConne | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| struct Connector(Box<NetworkConnector<Stream=Box<NetworkStream + Send>> + Send>); | struct Connector(Box<NetworkConnector<Stream=Box<NetworkStream + Send>> + Send + Sync>); | ||||||
|  |  | ||||||
| impl NetworkConnector for Connector { | impl NetworkConnector for Connector { | ||||||
|     type Stream = Box<NetworkStream + Send>; |     type Stream = Box<NetworkStream + Send>; | ||||||
|   | |||||||
| @@ -198,3 +198,8 @@ fn _assert_send<T: Send>() { | |||||||
|     _assert_send::<client::Request<net::Fresh>>(); |     _assert_send::<client::Request<net::Fresh>>(); | ||||||
|     _assert_send::<client::Response>(); |     _assert_send::<client::Response>(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[allow(unconditional_recursion)] | ||||||
|  | fn _assert_sync<T: Sync>() { | ||||||
|  |     _assert_sync::<Client>(); | ||||||
|  | } | ||||||
|   | |||||||
| @@ -144,12 +144,12 @@ impl NetworkConnector for MockConnector { | |||||||
| /// | /// | ||||||
| /// Otherwise, it behaves the same as `MockConnector`. | /// Otherwise, it behaves the same as `MockConnector`. | ||||||
| pub struct ChannelMockConnector { | pub struct ChannelMockConnector { | ||||||
|     calls: Sender<String>, |     calls: Mutex<Sender<String>>, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl ChannelMockConnector { | impl ChannelMockConnector { | ||||||
|     pub fn new(calls: Sender<String>) -> ChannelMockConnector { |     pub fn new(calls: Sender<String>) -> ChannelMockConnector { | ||||||
|         ChannelMockConnector { calls: calls } |         ChannelMockConnector { calls: Mutex::new(calls) } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -158,13 +158,13 @@ impl NetworkConnector for ChannelMockConnector { | |||||||
|     #[inline] |     #[inline] | ||||||
|     fn connect(&self, _host: &str, _port: u16, _scheme: &str) |     fn connect(&self, _host: &str, _port: u16, _scheme: &str) | ||||||
|             -> ::Result<MockStream> { |             -> ::Result<MockStream> { | ||||||
|         self.calls.send("connect".into()).unwrap(); |         self.calls.lock().unwrap().send("connect".into()).unwrap(); | ||||||
|         Ok(MockStream::new()) |         Ok(MockStream::new()) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     #[inline] |     #[inline] | ||||||
|     fn set_ssl_verifier(&mut self, _verifier: ContextVerifier) { |     fn set_ssl_verifier(&mut self, _verifier: ContextVerifier) { | ||||||
|         self.calls.send("set_ssl_verifier".into()).unwrap(); |         self.calls.lock().unwrap().send("set_ssl_verifier".into()).unwrap(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -317,7 +317,7 @@ impl NetworkStream for HttpStream { | |||||||
| pub struct HttpConnector(pub Option<ContextVerifier>); | pub struct HttpConnector(pub Option<ContextVerifier>); | ||||||
|  |  | ||||||
| /// A method that can set verification methods on an SSL context | /// A method that can set verification methods on an SSL context | ||||||
| pub type ContextVerifier = Box<Fn(&mut SslContext) -> () + Send>; | pub type ContextVerifier = Box<Fn(&mut SslContext) -> () + Send + Sync>; | ||||||
|  |  | ||||||
| impl NetworkConnector for HttpConnector { | impl NetworkConnector for HttpConnector { | ||||||
|     type Stream = HttpStream; |     type Stream = HttpStream; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user