feat(client): impl Sync for Client
Connector::connect already used &self, and so would require synchronization to be handled per connector anyway. Adding Sync to the Client allows users to setup config for a Client once, such as using a single connection Pool, and then making requests across multiple threads. Closes #254 BREAKING CHANGE: Connectors and Protocols passed to the `Client` must now also have a `Sync` bounds, but this shouldn't break default usage.
This commit is contained in:
		| @@ -9,7 +9,7 @@ | ||||
| //! | ||||
| //! ```no_run | ||||
| //! # use hyper::Client; | ||||
| //! let mut client = Client::new(); | ||||
| //! let client = Client::new(); | ||||
| //! | ||||
| //! let res = client.get("http://example.domain").send().unwrap(); | ||||
| //! assert_eq!(res.status, hyper::Ok); | ||||
| @@ -23,7 +23,7 @@ | ||||
| //! | ||||
| //! ```no_run | ||||
| //! # use hyper::Client; | ||||
| //! let mut client = Client::new(); | ||||
| //! let client = Client::new(); | ||||
| //! | ||||
| //! let res = client.post("http://example.domain") | ||||
| //!     .body("foo=bar") | ||||
| @@ -31,6 +31,30 @@ | ||||
| //!     .unwrap(); | ||||
| //! 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::io::{self, copy, Read}; | ||||
| use std::iter::Extend; | ||||
| @@ -61,7 +85,7 @@ use http::h1::Http11Protocol; | ||||
| /// | ||||
| /// Clients can handle things such as: redirect policy, connection pooling. | ||||
| pub struct Client { | ||||
|     protocol: Box<Protocol + Send>, | ||||
|     protocol: Box<Protocol + Send + Sync>, | ||||
|     redirect_policy: RedirectPolicy, | ||||
| } | ||||
|  | ||||
| @@ -79,12 +103,12 @@ impl Client { | ||||
|  | ||||
|     /// Create a new client with a specific connector. | ||||
|     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)) | ||||
|     } | ||||
|  | ||||
|     /// 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 { | ||||
|             protocol: Box::new(protocol), | ||||
|             redirect_policy: Default::default() | ||||
| @@ -102,33 +126,33 @@ impl Client { | ||||
|     } | ||||
|  | ||||
|     /// 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) | ||||
|     } | ||||
|  | ||||
|     /// 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) | ||||
|     } | ||||
|  | ||||
|     /// 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) | ||||
|     } | ||||
|  | ||||
|     /// 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) | ||||
|     } | ||||
|  | ||||
|     /// 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) | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /// 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 { | ||||
|             client: self, | ||||
|             method: method, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user