Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Shared via Rust Playground
#![feature(pattern)]
use std::str::pattern::Pattern;
use std::marker::PhantomData;
#[derive(PartialEq, Eq)]
enum Method {
Get,
Post,
Put,
Head,
}
struct Req<'a> {
method: Method,
location: &'a str,
content: &'a str,
}
#[derive(Debug)]
struct Resp(u16);
trait Handler<'a, Context> {
fn handle(&'a self, c: Context, req: &'a Req<'a>) -> Option<Resp>;
}
struct Router<P, H, C=()>(Method, P, H, PhantomData<C>);
struct Chain<A, B, C=()>(A, B, PhantomData<C>);
impl<
'a,
C: Clone,
A: Handler<'a, C>,
B: Handler<'a, C>
> Handler<'a, C> for Chain<A, B, C> {
fn handle(&'a self, c: C, req: &'a Req<'a>) -> Option<Resp> {
let c_clone = c.clone();
self.0.handle(c, req).or_else(|| self.1.handle(c_clone, req))
}
}
impl<
'a,
C,
P: Pattern<'a> + Clone,
H: Handler<'a, C>
> Router<P, H, C> {
fn new(m: Method, p: P, h: H) -> Self {
Router(m, p, h, PhantomData)
}
fn get(p: P, h: H) -> Self {
Self::new(Method::Get, p, h)
}
}
impl<'a, C, A: Handler<'a, C>, B: Handler<'a, C>> Chain<A, B, C> {
fn new(a: A, b: B) -> Chain<A, B, C> {
Chain(a, b, PhantomData)
}
}
trait HandleOr<'a, C>: Sized + Handler<'a, C> {
fn or_else<Other: Handler<'a, C>>(
self,
other: Other
) -> Chain<Self, Other, C> {
Chain::new(self, other)
}
fn or_new<
OP: Pattern<'a> + Clone, OH: Handler<'a, C>
>(
self,
m: Method,
p: OP,
h: OH
) -> Chain<Self, Router<OP, OH, C>, C> {
self.or_else(Router::new(m, p, h))
}
fn or_get<
OP: Pattern<'a> + Clone, OH: Handler<'a, C>
>(
self,
p: OP,
h: OH
) -> Chain<Self, Router<OP, OH, C>, C> {
self.or_else(Router::get(p, h))
}
}
impl<'a, C, H: Handler<'a, C>> HandleOr<'a, C> for H { }
impl<
'a,
C,
P: Pattern<'a> + Clone,
H: Handler<'a, C>
> Handler<'a, C> for Router<P, H, C> {
fn handle(&'a self, c: C, req: &'a Req<'a>) -> Option<Resp> {
if req.method == self.0 && req.location.contains(self.1.clone()) {
self.2.handle(c, req)
} else {
None
}
}
}
impl<
'a,
C:,
F: Fn(C, &'a Req<'a>) -> Option<Resp>
> Handler<'a, C> for F {
fn handle(&'a self, c: C, req: &'a Req<'a>) -> Option<Resp> {
self(c, req)
}
}
fn main() {
println!(
"{:?}",
Router::get("/test", |(), _| Some(Resp(200)))
.or_get("/something_else", |(), _| Some(Resp(100)))
.or_get("/last_thing", |(), _| Some(Resp(404)))
.handle(
(),
&Req {
method: Method::Get,
location: "/last_thing",
content: "Hello!",
}
)
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment