use crate::server::{Request, ResponseWriter, ResponseWritten, Result};
use async_dup::Arc;
use futures_util::io::{AsyncRead, AsyncWrite};
use http::{Method, StatusCode};
use path_tree::PathTree;
use std::future::Future;
use std::pin::Pin;
pub type Params = Vec<(String, String)>;
#[derive(Clone)]
pub struct Router<W>
where
W: AsyncRead + AsyncWrite + Clone + Send + Sync + Unpin + 'static,
{
tree: Arc<PathTree<Box<dyn Endpoint<W>>>>,
data: Arc<Option<DataMap>>,
}
impl<W> Router<W>
where
W: AsyncRead + AsyncWrite + Clone + Send + Sync + Unpin + 'static,
{
pub fn build() -> RouterBuilder<W> {
RouterBuilder::new()
}
pub async fn route(
&self,
mut req: Request,
mut resp_wtr: ResponseWriter<W>,
) -> Result<ResponseWritten> {
let path = "/".to_owned() + req.method().as_str() + req.uri().path();
match self.tree.find(&path) {
Some((endpoint, params)) => {
let params: Vec<(String, String)> = params
.into_iter()
.map(|(a, b)| (a.to_owned(), b.to_owned()))
.collect();
let extensions_mut = req.extensions_mut();
if let Some(ref data) = *self.data {
extensions_mut.insert(data.clone());
}
extensions_mut.insert(params);
endpoint.call(req, resp_wtr).await
}
None => {
resp_wtr.set_status(StatusCode::NOT_FOUND);
resp_wtr.send().await
}
}
}
}
pub struct RouterBuilder<W>
where
W: AsyncRead + AsyncWrite + Clone + Send + Sync + Unpin + 'static,
{
tree: PathTree<Box<dyn Endpoint<W>>>,
data: Option<type_map::concurrent::TypeMap>,
}
impl<W> RouterBuilder<W>
where
W: AsyncRead + AsyncWrite + Clone + Send + Sync + Unpin + 'static,
{
fn new() -> Self {
Self {
tree: PathTree::new(),
data: None,
}
}
pub fn at(self, method: Method, path: &str, endpoint: impl Endpoint<W>) -> Self {
let mut this = self;
let path = "/".to_owned() + method.as_str() + path;
this.tree.insert(&path, Box::new(endpoint));
this
}
pub fn data<T: Send + Sync + 'static>(self, data: T) -> Self {
self.wrapped_data(Data::new(data))
}
pub fn wrapped_data<T: Send + Sync + 'static>(mut self, data: T) -> Self {
let mut map = self
.data
.take()
.unwrap_or_else(type_map::concurrent::TypeMap::new);
map.insert(data);
self.data = Some(map);
self
}
pub fn finish(self) -> Router<W> {
Router {
tree: Arc::new(self.tree),
data: Arc::new(self.data.map(Data::new).map(DataMap)),
}
}
}
pub trait Endpoint<W>: Send + Sync + 'static
where
W: AsyncRead + AsyncWrite + Clone + Send + Sync + Unpin + 'static,
{
fn call(
&self,
req: Request,
resp_wtr: ResponseWriter<W>,
) -> BoxFuture<Result<ResponseWritten>>;
}
impl<F: Send + Sync + 'static, Fut, Res, W> Endpoint<W> for F
where
F: Fn(Request, ResponseWriter<W>) -> Fut,
Fut: Future<Output = Result<Res>> + Send + 'static,
Res: Into<ResponseWritten>,
W: AsyncRead + AsyncWrite + Clone + Send + Sync + Unpin + 'static,
{
fn call(
&self,
req: Request,
resp: ResponseWriter<W>,
) -> BoxFuture<Result<ResponseWritten>> {
let fut = (self)(req, resp);
Box::pin(async move {
let res = fut.await?;
Ok(res.into())
})
}
}
pub struct Data<T>(Arc<T>);
impl<T> Data<T> {
pub fn new(t: T) -> Self {
Data(Arc::new(t))
}
pub fn from_arc(arc: Arc<T>) -> Self {
Data(arc)
}
}
impl<T> std::ops::Deref for Data<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&*self.0
}
}
impl<T> Clone for Data<T> {
fn clone(&self) -> Self {
Data(Arc::clone(&self.0))
}
}
#[derive(Clone)]
struct DataMap(Data<type_map::concurrent::TypeMap>);
pub trait RouterRequestExt {
fn data<T: Send + Sync + 'static>(&self) -> Option<Data<T>>;
fn params(&self) -> Option<&Params>;
fn get_param(&self, key: &str) -> Option<&str>;
}
impl RouterRequestExt for crate::Request {
fn data<T: Send + Sync + 'static>(&self) -> Option<Data<T>> {
self.extensions()
.get::<DataMap>()
.and_then(|x| x.0.get::<Data<T>>())
.cloned()
}
fn params(&self) -> Option<&Params> {
self.extensions().get::<Params>()
}
fn get_param(&self, key: &str) -> Option<&str> {
if let Some(params) = self.extensions().get::<Params>() {
for (k, v) in params {
if key == k {
return Some(v);
}
}
}
None
}
}
pub(crate) type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;