Skip to content

Commit 9289690

Browse files
committed
feat: route_dyn & fix doc test
1 parent bc23d10 commit 9289690

File tree

13 files changed

+84
-78
lines changed

13 files changed

+84
-78
lines changed

Cargo.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "haro"
3-
version = "0.1.0"
3+
version = "0.2.0"
44
edition = "2021"
55
description = "A simple and synchronous web framework written in and for Rust"
66
license = "MIT OR Apache-2.0"

examples/closure/main.rs

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/// Use `route_dyn` to register a handler with closure
2+
use std::sync::Arc;
3+
4+
use haro::{Application, DynHandler, Response};
5+
6+
fn main() {
7+
let mut app = Application::new("0:8080");
8+
app.route_dyn("/", hello("Haro"));
9+
app.run();
10+
}
11+
12+
fn hello(name: &str) -> DynHandler {
13+
let name = name.to_string();
14+
Arc::new(move |_| Response::str(&name))
15+
}

examples/cookie/main.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
use std::sync::Arc;
22

33
use cookie::Cookie;
4+
use haro::{middleware, Application, DynHandler, Request, Response};
45
use http::header::SET_COOKIE;
56
use serde_json::json;
6-
use haro::{
7-
middleware::{self, DynHandler},
8-
Application, Request, Response,
9-
};
107

118
fn main() {
129
let mut app = Application::new("0:8080");
@@ -34,7 +31,7 @@ fn hello(req: Request) -> Response {
3431
fn session_middleware(next: DynHandler) -> DynHandler {
3532
Arc::new(move |req: Request| -> Response {
3633
let cookies = req.cookies();
37-
println!("get cookies: {:?}", cookies);
34+
println!("get cookies: {cookies:?}");
3835

3936
let mut res = next(req);
4037

examples/middleware/main.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
use std::sync::Arc;
22

3-
use haro::{
4-
middleware::{self, DynHandler},
5-
Application, Request, Response,
6-
};
3+
use haro::{middleware, Application, DynHandler, Request, Response};
74
use serde_json::json;
85

96
fn main() {

examples/template/main.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// NOTE: add `haro` crate with `full` or `template` feature flag to use database utilities.
22

3-
use tera::Context;
43
use haro::{Application, Request, Response};
4+
use tera::Context;
55

66
fn main() {
77
let mut app = Application::new("0:8080");

src/app.rs

+29-13
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ use std::{net::TcpListener, thread};
77
use log::{debug, info};
88

99
use crate::http::conn::Conn;
10-
use crate::middleware::{make_dyn_handler, Middleware};
10+
use crate::middleware::Middleware;
1111
use crate::pool::ThreadPool;
12-
use crate::router::{Handler, Router};
12+
use crate::router::{make_dyn_handler, DynHandler, Handler, Router};
1313
use crate::{Request, Response};
1414

1515
/// A web Application with routes and middlewares
@@ -65,7 +65,7 @@ impl Application {
6565
self.middlewares.push(Arc::new(middleware));
6666
}
6767

68-
/// Add a route into an `Application`
68+
/// Add a route using plain `fn` pointer
6969
/// # Example
7070
/// ```
7171
/// use haro::{Application, Request, Response, middleware};
@@ -78,6 +78,24 @@ impl Application {
7878
/// }
7979
/// ```
8080
pub fn route(&mut self, pattern: &'static str, handler: Handler) {
81+
self.route_dyn(pattern, make_dyn_handler(handler))
82+
}
83+
84+
/// Add a route using closure
85+
/// # Example
86+
/// ```
87+
/// use std::sync::Arc;
88+
/// use haro::{Application, DynHandler, Response};
89+
///
90+
/// let mut app = Application::new("0:8080");
91+
/// app.route_dyn("/", hello("Haro"));
92+
///
93+
/// fn hello(name: &str) -> DynHandler {
94+
/// let name = name.to_string();
95+
/// Arc::new(move |_| Response::str(&name))
96+
/// }
97+
/// ```
98+
pub fn route_dyn(&mut self, pattern: &'static str, handler: DynHandler) {
8199
self.router.add(pattern, handler);
82100
}
83101

@@ -105,21 +123,20 @@ impl Application {
105123
body: &[u8],
106124
) -> Response {
107125
let mut req = Request::new(method, uri, headers, body);
108-
let (params, handler) = self.router.dispatch(req.path());
126+
let (params, mut handler) = self.router.dispatch(req.path());
109127
req.params = params;
110128

111129
// TODO: how much benefits to move applying middlewares at begging to avoid do it every time in a new request.
112-
let mut dyn_handler = make_dyn_handler(handler);
113130
// apply middleware in reverse order
114131
for middleware in self.middlewares.iter().rev() {
115-
dyn_handler = middleware(dyn_handler);
132+
handler = middleware(handler);
116133
}
117-
dyn_handler(req)
134+
handler(req)
118135
}
119136

120137
/// Run the application, start listening on the specify address and start a worker pool to handle requests
121138
/// # Examples
122-
/// ```
139+
/// ```no_run
123140
/// use std::collections::HashMap;
124141
/// use haro::{Application, Request, Response};
125142
///
@@ -156,15 +173,14 @@ impl Application {
156173
fn handle_connection(router: Router, middlewares: Vec<Arc<Middleware>>, stream: TcpStream) {
157174
let mut conn = Conn::from(stream);
158175
let mut req = Request::from(&mut conn);
159-
let (params, handler) = router.dispatch(req.path());
176+
let (params, mut handler) = router.dispatch(req.path());
160177
req.params = params;
161178

162-
let mut dyn_handler = make_dyn_handler(handler);
163179
// apply middleware in reverse order
164180
for middleware in middlewares.iter().rev() {
165-
dyn_handler = middleware(dyn_handler);
181+
handler = middleware(handler);
166182
}
167-
let res = dyn_handler(req);
183+
let res = handler(req);
168184

169185
conn.write_all(res.to_string().as_bytes());
170186
conn.flush();
@@ -176,6 +192,6 @@ mod tests {
176192

177193
#[test]
178194
fn it_works() {
179-
let app = Application::new("0:65530").num_threads(2);
195+
Application::new("0:65530").num_threads(2);
180196
}
181197
}

src/http/response.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ impl Response {
2424
/// ```
2525
/// use std::collections::HashMap;
2626
/// use http::StatusCode;
27-
/// use haro::Resposne;
27+
/// use haro::Response;
2828
///
29-
/// let body = &Vec::new()
29+
/// let body = &Vec::new();
3030
/// let headers = HashMap::new();
3131
/// let res = Response::new(StatusCode::OK, body, headers);
3232
/// ```

src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
//! The "Hello, World!" of Haro is:
2121
//!
2222
//! ```rust,no_run
23-
//! use haro::{Applicatoin, Request, Response}
23+
//! use haro::{Application, Request, Response};
2424
//!
2525
//! fn main() {
2626
//! let mut app = Application::new("0:8000");
@@ -64,7 +64,7 @@ mod router;
6464
pub use crate::app::Application;
6565
pub use crate::http::request::Request;
6666
pub use crate::http::response::{redirect, Response};
67-
67+
pub use crate::router::{make_dyn_handler, DynHandler, Handler};
6868
#[cfg(feature = "template")]
6969
mod template;
7070

src/middleware.rs

+3-37
Original file line numberDiff line numberDiff line change
@@ -6,34 +6,15 @@ use std::time::Instant;
66

77
use log::info;
88

9-
use crate::{router::Handler, Request, Response};
9+
use crate::{DynHandler, Request, Response};
1010

11-
// pub trait Middleware {
12-
// fn process_request(&self, _: &mut Request) -> Option<Response> {
13-
// None
14-
// }
15-
// fn process_response(&self, _: &mut Response) {}
16-
// }
17-
18-
// pub struct Logging {}
19-
20-
// impl Middleware for Logging {
21-
// fn process_request(&self, req: &mut Request) -> Option<Response> {
22-
// info!("{} {}", req.method(), req.full_path());
23-
// None
24-
// }
25-
// }
26-
27-
/// Closure type of handler in order to capture environment variables, required when writing a middleware
28-
pub type DynHandler = Arc<dyn Fn(Request) -> Response>;
29-
30-
/// Function type for a middleware to receive a [`DynHandler`] and return a new [`DynHandler`]
11+
/// Function type for a middleware to receive a [`Handler`] and return a new [`Handler`]
3112
pub type Middleware = fn(next: DynHandler) -> DynHandler;
3213

3314
/// Logging middleware to log every request and response time
3415
/// # Example
3516
/// ```
36-
/// use haro::{Application, middleware}
17+
/// use haro::{Application, middleware};
3718
///
3819
/// let mut app = Application::new("0:8080");
3920
/// app.middleware(middleware::logging);
@@ -52,18 +33,3 @@ pub fn logging(next: DynHandler) -> DynHandler {
5233
res
5334
})
5435
}
55-
56-
/// Change a fn pointer to a closure
57-
/// # Example
58-
/// ```
59-
/// use haro::{Request, Response, middleware};
60-
///
61-
/// fn handler(_:Request) -> Response{
62-
/// Response::str("hello")
63-
/// }
64-
///
65-
/// let dyn_handler = middleware::make_dyn_handler(handler);
66-
/// ```
67-
pub fn make_dyn_handler(h: Handler) -> DynHandler {
68-
Arc::new(move |req: Request| -> Response { h(req) })
69-
}

src/router.rs

+25-6
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,25 @@
11
use std::collections::HashMap;
22
use std::fmt::Display;
3+
use std::sync::Arc;
34

45
use http::StatusCode;
56
use regex::Regex;
67

78
use crate::http::request::Request;
89
use crate::http::response::Response;
910

11+
/// Handler type that receive a [`Request`] and return a [`Response`]
1012
pub type Handler = fn(Request) -> Response;
13+
/// Closure type of handler in order to write a handler to capture environment variables
14+
pub type DynHandler = Arc<dyn Fn(Request) -> Response + Send + Sync>;
1115

1216
#[derive(Default, Clone)]
1317
pub struct Router {
14-
routes: Vec<(Rule, Handler)>,
18+
routes: Vec<(Rule, DynHandler)>,
1519
}
1620

1721
impl Router {
18-
pub fn add(&mut self, pattern: &'static str, handler: Handler) {
22+
pub fn add(&mut self, pattern: &'static str, handler: DynHandler) {
1923
let rule = Rule::from(pattern);
2024
self.routes.push((rule, handler));
2125
self.update_order()
@@ -27,13 +31,13 @@ impl Router {
2731
.sort_by(|a, b| b.0.num_parts.cmp(&a.0.num_parts));
2832
}
2933

30-
pub fn dispatch(&self, path: &str) -> (HashMap<String, String>, Handler) {
34+
pub fn dispatch(&self, path: &str) -> (HashMap<String, String>, DynHandler) {
3135
for (rule, handler) in &self.routes {
3236
if let Some(params) = rule._match(path) {
33-
return (params, *handler);
37+
return (params, handler.clone());
3438
}
3539
}
36-
(HashMap::new(), not_found)
40+
(HashMap::new(), make_dyn_handler(not_found))
3741
}
3842
}
3943

@@ -63,7 +67,7 @@ impl From<&'static str> for Rule {
6367
let mut has_regex = false;
6468
for part in pattern.split('/') {
6569
if let Some(stripped) = part.strip_prefix(':') {
66-
let regex_part = format!("(?P<{}>.+)", stripped);
70+
let regex_part = format!("(?P<{stripped}>.+)");
6771
parts.push(regex_part);
6872
has_regex = true
6973
} else if !part.is_empty() {
@@ -114,3 +118,18 @@ fn not_found(_req: Request) -> Response {
114118
HashMap::new(),
115119
)
116120
}
121+
122+
/// Change a fn pointer to a closure
123+
/// # Example
124+
/// ```
125+
/// use haro::{Request, Response, middleware,make_dyn_handler};
126+
///
127+
/// fn handler(_:Request) -> Response{
128+
/// Response::str("hello")
129+
/// }
130+
///
131+
/// let dyn_handler = make_dyn_handler(handler);
132+
/// ```
133+
pub fn make_dyn_handler(h: Handler) -> DynHandler {
134+
Arc::new(move |req: Request| -> Response { h(req) })
135+
}

src/template.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ pub(crate) static TEMPLATES: Lazy<Tera> = Lazy::new(|| {
55
let tera = match Tera::new("templates/**/*") {
66
Ok(t) => t,
77
Err(e) => {
8-
println!("Parsing error(s): {}", e);
8+
println!("Parsing error(s): {e}");
99
::std::process::exit(1);
1010
}
1111
};

tests/test.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
use haro::{
2-
db,
3-
middleware::{self, DynHandler},
4-
Application, Request, Response,
5-
};
1+
use haro::{db, middleware, Application, DynHandler, Request, Response};
62
use http::StatusCode;
73
use serde::{Deserialize, Serialize};
84
use serde_json::json;

0 commit comments

Comments
 (0)