Skip to content

Commit 50bc628

Browse files
Fishrock123jbr
andcommitted
Server: require State to be Clone
Alternative to #642 This approach is more flexible but requires the user ensure that their state implements/derives `Clone`, or is wrapped in an `Arc`. Co-authored-by: Jacob Rothstein <hi@jbr.me>
1 parent be1c3a9 commit 50bc628

27 files changed

+103
-92
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ route-recognizer = "0.2.0"
4444
logtest = "2.0.0"
4545
async-trait = "0.1.36"
4646
futures-util = "0.3.5"
47+
pin-project-lite = "0.1.7"
4748

4849
[dev-dependencies]
4950
async-std = { version = "1.6.0", features = ["unstable", "attributes"] }

examples/graphql.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::sync::Arc;
2+
13
use async_std::task;
24
use juniper::{http::graphiql, http::GraphQLRequest, RootNode};
35
use std::sync::RwLock;
@@ -37,8 +39,9 @@ impl NewUser {
3739
}
3840
}
3941

42+
#[derive(Clone)]
4043
pub struct State {
41-
users: RwLock<Vec<User>>,
44+
users: Arc<RwLock<Vec<User>>>,
4245
}
4346
impl juniper::Context for State {}
4447

@@ -96,7 +99,7 @@ async fn handle_graphiql(_: Request<State>) -> tide::Result<impl Into<Response>>
9699
fn main() -> std::io::Result<()> {
97100
task::block_on(async {
98101
let mut app = Server::with_state(State {
99-
users: RwLock::new(Vec::new()),
102+
users: Arc::new(RwLock::new(Vec::new())),
100103
});
101104
app.at("/").get(Redirect::permanent("/graphiql"));
102105
app.at("/graphql").post(handle_graphql);

examples/middleware.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ struct User {
1111
name: String,
1212
}
1313

14-
#[derive(Default, Debug)]
14+
#[derive(Clone, Default, Debug)]
1515
struct UserDatabase;
1616
impl UserDatabase {
1717
async fn find_user(&self) -> Option<User> {
@@ -62,7 +62,7 @@ impl RequestCounterMiddleware {
6262
struct RequestCount(usize);
6363

6464
#[tide::utils::async_trait]
65-
impl<State: Send + Sync + 'static> Middleware<State> for RequestCounterMiddleware {
65+
impl<State: Clone + Send + Sync + 'static> Middleware<State> for RequestCounterMiddleware {
6666
async fn handle(&self, mut req: Request<State>, next: Next<'_, State>) -> Result {
6767
let count = self.requests_counted.fetch_add(1, Ordering::Relaxed);
6868
tide::log::trace!("request counter", { count: count });

examples/upload.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::sync::Arc;
2+
13
use async_std::{fs::OpenOptions, io};
24
use tempfile::TempDir;
35
use tide::prelude::*;
@@ -6,15 +8,15 @@ use tide::{Body, Request, Response, StatusCode};
68
#[async_std::main]
79
async fn main() -> Result<(), std::io::Error> {
810
tide::log::start();
9-
let mut app = tide::with_state(tempfile::tempdir()?);
11+
let mut app = tide::with_state(Arc::new(tempfile::tempdir()?));
1012

1113
// To test this example:
1214
// $ cargo run --example upload
1315
// $ curl -T ./README.md locahost:8080 # this writes the file to a temp directory
1416
// $ curl localhost:8080/README.md # this reads the file from the same temp directory
1517

1618
app.at(":file")
17-
.put(|req: Request<TempDir>| async move {
19+
.put(|req: Request<Arc<TempDir>>| async move {
1820
let path: String = req.param("file")?;
1921
let fs_path = req.state().path().join(path);
2022

@@ -33,7 +35,7 @@ async fn main() -> Result<(), std::io::Error> {
3335

3436
Ok(json!({ "bytes": bytes_written }))
3537
})
36-
.get(|req: Request<TempDir>| async move {
38+
.get(|req: Request<Arc<TempDir>>| async move {
3739
let path: String = req.param("file")?;
3840
let fs_path = req.state().path().join(path);
3941

src/cookies/middleware.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ impl CookiesMiddleware {
3535
}
3636

3737
#[async_trait]
38-
impl<State: Send + Sync + 'static> Middleware<State> for CookiesMiddleware {
38+
impl<State: Clone + Send + Sync + 'static> Middleware<State> for CookiesMiddleware {
3939
async fn handle(&self, mut ctx: Request<State>, next: Next<'_, State>) -> crate::Result {
4040
let cookie_jar = if let Some(cookie_data) = ctx.ext::<CookieData>() {
4141
cookie_data.content.clone()

src/endpoint.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ use crate::{Middleware, Request, Response};
4545
///
4646
/// Tide routes will also accept endpoints with `Fn` signatures of this form, but using the `async` keyword has better ergonomics.
4747
#[async_trait]
48-
pub trait Endpoint<State: Send + Sync + 'static>: Send + Sync + 'static {
48+
pub trait Endpoint<State: Clone + Send + Sync + 'static>: Send + Sync + 'static {
4949
/// Invoke the endpoint within the given context
5050
async fn call(&self, req: Request<State>) -> crate::Result;
5151
}
@@ -55,7 +55,7 @@ pub(crate) type DynEndpoint<State> = dyn Endpoint<State>;
5555
#[async_trait]
5656
impl<State, F, Fut, Res> Endpoint<State> for F
5757
where
58-
State: Send + Sync + 'static,
58+
State: Clone + Send + Sync + 'static,
5959
F: Send + Sync + 'static + Fn(Request<State>) -> Fut,
6060
Fut: Future<Output = Result<Res>> + Send + 'static,
6161
Res: Into<Response> + 'static,
@@ -93,7 +93,7 @@ impl<E, State> std::fmt::Debug for MiddlewareEndpoint<E, State> {
9393

9494
impl<E, State> MiddlewareEndpoint<E, State>
9595
where
96-
State: Send + Sync + 'static,
96+
State: Clone + Send + Sync + 'static,
9797
E: Endpoint<State>,
9898
{
9999
pub fn wrap_with_middleware(ep: E, middleware: &[Arc<dyn Middleware<State>>]) -> Self {
@@ -107,7 +107,7 @@ where
107107
#[async_trait]
108108
impl<E, State> Endpoint<State> for MiddlewareEndpoint<E, State>
109109
where
110-
State: Send + Sync + 'static,
110+
State: Clone + Send + Sync + 'static,
111111
E: Endpoint<State>,
112112
{
113113
async fn call(&self, req: Request<State>) -> crate::Result {

src/fs/serve_dir.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ impl ServeDir {
2121
#[async_trait::async_trait]
2222
impl<State> Endpoint<State> for ServeDir
2323
where
24-
State: Send + Sync + 'static,
24+
State: Clone + Send + Sync + 'static,
2525
{
2626
async fn call(&self, req: Request<State>) -> Result {
2727
let path = req.url().path();
@@ -60,8 +60,6 @@ where
6060
mod test {
6161
use super::*;
6262

63-
use async_std::sync::Arc;
64-
6563
use std::fs::{self, File};
6664
use std::io::Write;
6765

@@ -83,7 +81,7 @@ mod test {
8381
let request = crate::http::Request::get(
8482
crate::http::Url::parse(&format!("http://localhost/{}", path)).unwrap(),
8583
);
86-
crate::Request::new(Arc::new(()), request, vec![])
84+
crate::Request::new((), request, vec![])
8785
}
8886

8987
#[async_std::test]

src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ pub fn new() -> server::Server<()> {
259259
/// use tide::Request;
260260
///
261261
/// /// The shared application state.
262+
/// #[derive(Clone)]
262263
/// struct State {
263264
/// name: String,
264265
/// }
@@ -279,7 +280,7 @@ pub fn new() -> server::Server<()> {
279280
/// ```
280281
pub fn with_state<State>(state: State) -> server::Server<State>
281282
where
282-
State: Send + Sync + 'static,
283+
State: Clone + Send + Sync + 'static,
283284
{
284285
Server::with_state(state)
285286
}

src/listener/concurrent_listener.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use futures_util::stream::{futures_unordered::FuturesUnordered, StreamExt};
3535
#[derive(Default)]
3636
pub struct ConcurrentListener<State>(Vec<Box<dyn Listener<State>>>);
3737

38-
impl<State: Send + Sync + 'static> ConcurrentListener<State> {
38+
impl<State: Clone + Send + Sync + 'static> ConcurrentListener<State> {
3939
/// creates a new ConcurrentListener
4040
pub fn new() -> Self {
4141
Self(vec![])
@@ -78,7 +78,7 @@ impl<State: Send + Sync + 'static> ConcurrentListener<State> {
7878
}
7979

8080
#[async_trait::async_trait]
81-
impl<State: Send + Sync + 'static> Listener<State> for ConcurrentListener<State> {
81+
impl<State: Clone + Send + Sync + 'static> Listener<State> for ConcurrentListener<State> {
8282
async fn listen(&mut self, app: Server<State>) -> io::Result<()> {
8383
let mut futures_unordered = FuturesUnordered::new();
8484

src/listener/failover_listener.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use async_std::io;
3535
#[derive(Default)]
3636
pub struct FailoverListener<State>(Vec<Box<dyn Listener<State>>>);
3737

38-
impl<State: Send + Sync + 'static> FailoverListener<State> {
38+
impl<State: Clone + Send + Sync + 'static> FailoverListener<State> {
3939
/// creates a new FailoverListener
4040
pub fn new() -> Self {
4141
Self(vec![])
@@ -80,7 +80,7 @@ impl<State: Send + Sync + 'static> FailoverListener<State> {
8080
}
8181

8282
#[async_trait::async_trait]
83-
impl<State: Send + Sync + 'static> Listener<State> for FailoverListener<State> {
83+
impl<State: Clone + Send + Sync + 'static> Listener<State> for FailoverListener<State> {
8484
async fn listen(&mut self, app: Server<State>) -> io::Result<()> {
8585
for listener in self.0.iter_mut() {
8686
let app = app.clone();

src/listener/parsed_listener.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ impl Display for ParsedListener {
3131
}
3232

3333
#[async_trait::async_trait]
34-
impl<State: Send + Sync + 'static> Listener<State> for ParsedListener {
34+
impl<State: Clone + Send + Sync + 'static> Listener<State> for ParsedListener {
3535
async fn listen(&mut self, app: Server<State>) -> io::Result<()> {
3636
match self {
3737
#[cfg(unix)]

src/listener/tcp_listener.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ impl TcpListener {
5151
}
5252
}
5353

54-
fn handle_tcp<State: Send + Sync + 'static>(app: Server<State>, stream: TcpStream) {
54+
fn handle_tcp<State: Clone + Send + Sync + 'static>(app: Server<State>, stream: TcpStream) {
5555
task::spawn(async move {
5656
let local_addr = stream.local_addr().ok();
5757
let peer_addr = stream.peer_addr().ok();
@@ -69,7 +69,7 @@ fn handle_tcp<State: Send + Sync + 'static>(app: Server<State>, stream: TcpStrea
6969
}
7070

7171
#[async_trait::async_trait]
72-
impl<State: Send + Sync + 'static> Listener<State> for TcpListener {
72+
impl<State: Clone + Send + Sync + 'static> Listener<State> for TcpListener {
7373
async fn listen(&mut self, app: Server<State>) -> io::Result<()> {
7474
self.connect().await?;
7575
let listener = self.listener()?;

src/listener/to_listener.rs

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ use std::net::ToSocketAddrs;
5252
/// # Other implementations
5353
/// See below for additional provided implementations of ToListener.
5454
55-
pub trait ToListener<State: Send + Sync + 'static> {
55+
pub trait ToListener<State: Clone + Send + Sync + 'static> {
5656
type Listener: Listener<State>;
5757
/// Transform self into a
5858
/// [`Listener`](crate::listener::Listener). Unless self is
@@ -63,7 +63,7 @@ pub trait ToListener<State: Send + Sync + 'static> {
6363
fn to_listener(self) -> io::Result<Self::Listener>;
6464
}
6565

66-
impl<State: Send + Sync + 'static> ToListener<State> for Url {
66+
impl<State: Clone + Send + Sync + 'static> ToListener<State> for Url {
6767
type Listener = ParsedListener;
6868

6969
fn to_listener(self) -> io::Result<Self::Listener> {
@@ -106,14 +106,14 @@ impl<State: Send + Sync + 'static> ToListener<State> for Url {
106106
}
107107
}
108108

109-
impl<State: Send + Sync + 'static> ToListener<State> for String {
109+
impl<State: Clone + Send + Sync + 'static> ToListener<State> for String {
110110
type Listener = ParsedListener;
111111
fn to_listener(self) -> io::Result<Self::Listener> {
112112
ToListener::<State>::to_listener(self.as_str())
113113
}
114114
}
115115

116-
impl<State: Send + Sync + 'static> ToListener<State> for &str {
116+
impl<State: Clone + Send + Sync + 'static> ToListener<State> for &str {
117117
type Listener = ParsedListener;
118118

119119
fn to_listener(self) -> io::Result<Self::Listener> {
@@ -133,36 +133,36 @@ impl<State: Send + Sync + 'static> ToListener<State> for &str {
133133
}
134134

135135
#[cfg(unix)]
136-
impl<State: Send + Sync + 'static> ToListener<State> for async_std::path::PathBuf {
136+
impl<State: Clone + Send + Sync + 'static> ToListener<State> for async_std::path::PathBuf {
137137
type Listener = UnixListener;
138138
fn to_listener(self) -> io::Result<Self::Listener> {
139139
Ok(UnixListener::from_path(self))
140140
}
141141
}
142142

143143
#[cfg(unix)]
144-
impl<State: Send + Sync + 'static> ToListener<State> for std::path::PathBuf {
144+
impl<State: Clone + Send + Sync + 'static> ToListener<State> for std::path::PathBuf {
145145
type Listener = UnixListener;
146146
fn to_listener(self) -> io::Result<Self::Listener> {
147147
Ok(UnixListener::from_path(self))
148148
}
149149
}
150150

151-
impl<State: Send + Sync + 'static> ToListener<State> for async_std::net::TcpListener {
151+
impl<State: Clone + Send + Sync + 'static> ToListener<State> for async_std::net::TcpListener {
152152
type Listener = TcpListener;
153153
fn to_listener(self) -> io::Result<Self::Listener> {
154154
Ok(TcpListener::from_listener(self))
155155
}
156156
}
157157

158-
impl<State: Send + Sync + 'static> ToListener<State> for std::net::TcpListener {
158+
impl<State: Clone + Send + Sync + 'static> ToListener<State> for std::net::TcpListener {
159159
type Listener = TcpListener;
160160
fn to_listener(self) -> io::Result<Self::Listener> {
161161
Ok(TcpListener::from_listener(self))
162162
}
163163
}
164164

165-
impl<State: Send + Sync + 'static> ToListener<State> for (&str, u16) {
165+
impl<State: Clone + Send + Sync + 'static> ToListener<State> for (&str, u16) {
166166
type Listener = TcpListener;
167167

168168
fn to_listener(self) -> io::Result<Self::Listener> {
@@ -171,65 +171,67 @@ impl<State: Send + Sync + 'static> ToListener<State> for (&str, u16) {
171171
}
172172

173173
#[cfg(unix)]
174-
impl<State: Send + Sync + 'static> ToListener<State> for async_std::os::unix::net::UnixListener {
174+
impl<State: Clone + Send + Sync + 'static> ToListener<State>
175+
for async_std::os::unix::net::UnixListener
176+
{
175177
type Listener = UnixListener;
176178
fn to_listener(self) -> io::Result<Self::Listener> {
177179
Ok(UnixListener::from_listener(self))
178180
}
179181
}
180182

181183
#[cfg(unix)]
182-
impl<State: Send + Sync + 'static> ToListener<State> for std::os::unix::net::UnixListener {
184+
impl<State: Clone + Send + Sync + 'static> ToListener<State> for std::os::unix::net::UnixListener {
183185
type Listener = UnixListener;
184186
fn to_listener(self) -> io::Result<Self::Listener> {
185187
Ok(UnixListener::from_listener(self))
186188
}
187189
}
188190

189-
impl<State: Send + Sync + 'static> ToListener<State> for TcpListener {
191+
impl<State: Clone + Send + Sync + 'static> ToListener<State> for TcpListener {
190192
type Listener = Self;
191193
fn to_listener(self) -> io::Result<Self::Listener> {
192194
Ok(self)
193195
}
194196
}
195197

196198
#[cfg(unix)]
197-
impl<State: Send + Sync + 'static> ToListener<State> for UnixListener {
199+
impl<State: Clone + Send + Sync + 'static> ToListener<State> for UnixListener {
198200
type Listener = Self;
199201
fn to_listener(self) -> io::Result<Self::Listener> {
200202
Ok(self)
201203
}
202204
}
203205

204-
impl<State: Send + Sync + 'static> ToListener<State> for ConcurrentListener<State> {
206+
impl<State: Clone + Send + Sync + 'static> ToListener<State> for ConcurrentListener<State> {
205207
type Listener = Self;
206208
fn to_listener(self) -> io::Result<Self::Listener> {
207209
Ok(self)
208210
}
209211
}
210212

211-
impl<State: Send + Sync + 'static> ToListener<State> for ParsedListener {
213+
impl<State: Clone + Send + Sync + 'static> ToListener<State> for ParsedListener {
212214
type Listener = Self;
213215
fn to_listener(self) -> io::Result<Self::Listener> {
214216
Ok(self)
215217
}
216218
}
217219

218-
impl<State: Send + Sync + 'static> ToListener<State> for FailoverListener<State> {
220+
impl<State: Clone + Send + Sync + 'static> ToListener<State> for FailoverListener<State> {
219221
type Listener = Self;
220222
fn to_listener(self) -> io::Result<Self::Listener> {
221223
Ok(self)
222224
}
223225
}
224226

225-
impl<State: Send + Sync + 'static> ToListener<State> for std::net::SocketAddr {
227+
impl<State: Clone + Send + Sync + 'static> ToListener<State> for std::net::SocketAddr {
226228
type Listener = TcpListener;
227229
fn to_listener(self) -> io::Result<Self::Listener> {
228230
Ok(TcpListener::from_addrs(vec![self]))
229231
}
230232
}
231233

232-
impl<TL: ToListener<State>, State: Send + Sync + 'static> ToListener<State> for Vec<TL> {
234+
impl<TL: ToListener<State>, State: Clone + Send + Sync + 'static> ToListener<State> for Vec<TL> {
233235
type Listener = ConcurrentListener<State>;
234236
fn to_listener(self) -> io::Result<Self::Listener> {
235237
let mut concurrent_listener = ConcurrentListener::new();

0 commit comments

Comments
 (0)